private ODataStreamReferenceValue ReadStreamPropertyValue() { if (!base.ReadingResponse) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonEntryAndFeedDeserializer_StreamPropertyInRequest); } ODataVersionChecker.CheckStreamReferenceProperty(base.Version); base.JsonReader.ReadStartObject(); ODataStreamReferenceValue value2 = null; if (base.JsonReader.NodeType != JsonNodeType.Property) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonEntryAndFeedDeserializer_CannotParseStreamReference); } string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__mediaresource", strB) != 0) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonEntryAndFeedDeserializer_CannotParseStreamReference); } value2 = this.ReadStreamReferenceValue(); if (base.JsonReader.NodeType != JsonNodeType.EndObject) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonEntryAndFeedDeserializer_CannotParseStreamReference); } base.JsonReader.Read(); return(value2); }
public static object ConvertFromUriLiteral(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference) { Exception exception; ExpressionToken token; ExceptionUtils.CheckArgumentNotNull <string>(value, "value"); if ((typeReference != null) && (model == null)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeRefWithoutModel); } if (model == null) { model = EdmCoreModel.Instance; } ExpressionLexer lexer = new ExpressionLexer(value, false); if (!lexer.TryPeekNextToken(out token, out exception)) { return(ODataUriConversionUtils.ConvertFromComplexOrCollectionValue(value, version, model, typeReference)); } object primitiveValue = lexer.ReadLiteralToken(); if (typeReference != null) { primitiveValue = ODataUriConversionUtils.VerifyAndCoerceUriPrimitiveLiteral(primitiveValue, model, typeReference, version); } if (primitiveValue is ISpatial) { ODataVersionChecker.CheckSpatialValue(version); } return(primitiveValue); }
private ISpatial ReadSpatialValue(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue) { ODataVersionChecker.CheckSpatialValue(base.Version); if (this.TryReadNullValue(expectedValueTypeReference, validateNullValue)) { return(null); } ISpatial spatial = null; if (base.JsonReader.NodeType == JsonNodeType.StartObject) { IDictionary <string, object> source = this.ReadObjectValue(base.JsonReader); GeoJsonObjectFormatter formatter = SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter(); if (expectedValueTypeReference.IsGeographyType()) { spatial = formatter.Read <Geography>(source); } else { spatial = formatter.Read <Geometry>(source); } } if (spatial == null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadSpatialPropertyValue); } return(spatial); }
/// <summary> /// Verifies that the given <paramref name="primitiveValue"/> is or can be coerced to <paramref name="expectedTypeReference"/>, and coerces it if necessary. /// </summary> /// <param name="primitiveValue">An EDM primitive value to verify.</param> /// <param name="model">Model to verify against.</param> /// <param name="expectedTypeReference">Expected type reference.</param> /// <param name="version">The version to use for reading.</param> /// <returns>Coerced version of the <paramref name="primitiveValue"/>.</returns> internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(primitiveValue, "primitiveValue"); ExceptionUtils.CheckArgumentNotNull(model, "model"); ExceptionUtils.CheckArgumentNotNull(expectedTypeReference, "expectedTypeReference"); // First deal with null literal ODataUriNullValue nullValue = primitiveValue as ODataUriNullValue; if (nullValue != null) { if (!expectedTypeReference.IsNullable) { throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName())); } IEdmType actualResolvedType = ValidationUtils.ValidateValueTypeName(model, nullValue.TypeName, expectedTypeReference.Definition.TypeKind); Debug.Assert(actualResolvedType != null, "This is a primitive-only codepath so actualResolvedType != null."); if (actualResolvedType.IsSpatial()) { ODataVersionChecker.CheckSpatialValue(version); } if (TypePromotionUtils.CanConvertTo(actualResolvedType.ToTypeReference(), expectedTypeReference)) { nullValue.TypeName = expectedTypeReference.ODataFullName(); return(nullValue); } throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralNullTypeVerificationFailure(expectedTypeReference.ODataFullName(), nullValue.TypeName)); } // Only other positive case is a numeric primitive that needs to be coerced IEdmPrimitiveTypeReference expectedPrimitiveTypeReference = expectedTypeReference.AsPrimitiveOrNull(); if (expectedPrimitiveTypeReference == null) { throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue)); } object coercedResult = CoerceNumericType(primitiveValue, expectedPrimitiveTypeReference.PrimitiveDefinition()); if (coercedResult != null) { return(coercedResult); } Type actualType = primitiveValue.GetType(); Type targetType = TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(expectedPrimitiveTypeReference)); // If target type is assignable from actual type, we're OK if (targetType.IsAssignableFrom(actualType)) { return(primitiveValue); } throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedPrimitiveTypeReference.ODataFullName(), primitiveValue)); }
private void WriteProperty(ODataProperty property, IEdmStructuredType owningType, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); if (!projectedProperties.ShouldSkipProperty(property.Name)) { WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty expectedProperty = WriterValidationUtils.ValidatePropertyDefined(property.Name, owningType); if (((expectedProperty != null) && expectedProperty.Type.IsSpatial()) || ((expectedProperty == null) && (property.Value is ISpatial))) { ODataVersionChecker.CheckSpatialValue(base.Version); } base.JsonWriter.WriteName(property.Name); object obj2 = property.Value; if (obj2 == null) { WriterValidationUtils.ValidateNullPropertyValue(expectedProperty, base.MessageWriterSettings.WriterBehavior, base.Model); base.JsonWriter.WriteValue((string)null); } else { bool isOpenPropertyType = ((owningType != null) && owningType.IsOpen) && (expectedProperty == null); if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(property.Name, obj2); } IEdmTypeReference propertyTypeReference = (expectedProperty == null) ? null : expectedProperty.Type; ODataComplexValue complexValue = obj2 as ODataComplexValue; if (complexValue != null) { this.WriteComplexValue(complexValue, propertyTypeReference, isOpenPropertyType, base.CreateDuplicatePropertyNamesChecker(), null); } else { ODataCollectionValue collectionValue = obj2 as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(base.Version, property.Name); this.WriteCollectionValue(collectionValue, propertyTypeReference, isOpenPropertyType); } else if (obj2 is ODataStreamReferenceValue) { if (!allowStreamProperty) { throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(property.Name)); } WriterValidationUtils.ValidateStreamReferenceProperty(property, expectedProperty, base.Version, base.WritingResponse); this.WriteStreamReferenceValue((ODataStreamReferenceValue)property.Value); } else { this.WritePrimitiveValue(obj2, null, propertyTypeReference); } } } } }
/// <summary> /// Converts a <see cref="ODataCollectionValue"/> to a string for use in a Url. /// </summary> /// <param name="collectionValue">Instance to convert.</param> /// <param name="model">Model to be used for validation. User model is optional. The EdmLib core model is expected as a minimum.</param> /// <param name="version">Version to be compliant with. Collection requires >= V3.</param> /// <param name="format">ODataFormat to use for the format of the literal.</param> /// <returns>A string representation of <paramref name="collectionValue"/> to be added to a Url.</returns> internal static string ConvertToUriCollectionLiteral(ODataCollectionValue collectionValue, IEdmModel model, ODataVersion version, ODataFormat format) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(collectionValue, "collectionValue"); ExceptionUtils.CheckArgumentNotNull(model, "model"); ODataVersionChecker.CheckCollectionValue(version); StringBuilder builder = new StringBuilder(); using (TextWriter textWriter = new StringWriter(builder, CultureInfo.InvariantCulture)) { ODataMessageWriterSettings messageWriterSettings = new ODataMessageWriterSettings() { Version = version, Indent = false }; if (format == ODataFormat.VerboseJson) { WriteJsonVerboseLiteral( model, messageWriterSettings, textWriter, (serializer) => serializer.WriteCollectionValue( collectionValue, null /*metadataTypeReference*/, false /*isOpenPropertyType*/)); } else if (format == ODataFormat.Json) { WriteJsonLightLiteral( model, messageWriterSettings, textWriter, (serializer) => serializer.WriteCollectionValue( collectionValue, null /*metadataTypeReference*/, false /*isTopLevelProperty*/, true /*isInUri*/, false /*isOpenPropertyType*/)); } else { throw new ArgumentException(ODataErrorStrings.ODataUriUtils_ConvertToUriLiteralUnsupportedFormat(format.ToString())); } } return(builder.ToString()); }
/// <summary> /// Writes a name/value pair for a property. /// </summary> /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param> /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param> /// <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="version">The protocol version used for writing.</param> private static void WriteProperty( JsonWriter jsonWriter, DataServiceMetadataProviderWrapper metadata, ODataProperty property, ResourceType owningType, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(jsonWriter != null, "jsonWriter != null"); ValidationUtils.ValidateProperty(property); ResourceProperty resourceProperty = ValidationUtils.ValidatePropertyDefined(property.Name, owningType); bool isOpenPropertyType = owningType != null && owningType.IsOpenType && resourceProperty == null; jsonWriter.WriteName(property.Name); object value = property.Value; if (value == null) { // verify that MultiValue properties are not null if (resourceProperty != null && resourceProperty.Kind == ResourcePropertyKind.MultiValue) { throw new ODataException(Strings.ODataWriter_MultiValuePropertiesMustNotHaveNullValue(resourceProperty.Name)); } jsonWriter.WriteValue(null); } else { ResourceType resourcePropertyType = resourceProperty == null ? null : resourceProperty.ResourceType; ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { WriteComplexValue(jsonWriter, metadata, complexValue, resourcePropertyType, isOpenPropertyType, version); } else { ODataMultiValue multiValue = value as ODataMultiValue; if (multiValue != null) { ODataVersionChecker.CheckMultiValueProperties(version, property.Name); WriteMultiValue(jsonWriter, metadata, multiValue, resourcePropertyType, isOpenPropertyType, version); } else { WritePrimitiveValue(jsonWriter, value, resourcePropertyType); } } } }
/// <summary> /// Try and parse spatial type from the json payload. /// </summary> /// <param name="jsonReader">The JSON reader to read from.</param> /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object /// (or the second property if the first one was odata.type).</param> /// <param name="inputContext">The input context with all the settings.</param> /// <param name="expectedValueTypeReference">Expected edm property type.</param> /// <param name="validateNullValue">true to validate null values; otherwise false.</param> /// <param name="recursionDepth">The recursion depth to start with.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param> /// <returns>An instance of the spatial type.</returns> internal static ISpatial ReadSpatialValue( BufferingJsonReader jsonReader, bool insideJsonObjectValue, ODataInputContext inputContext, IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue, int recursionDepth, string propertyName) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(inputContext != null, "inputContext != null"); Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null"); Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types"); // Note that we made sure that payload type detection will not return spatial for <V3 payloads // So the only way we can get a spatial type reference is if it comes from the model, // in which case we want to fail for <V3 payloads, since we can't report spatial values from such payloads. ODataVersionChecker.CheckSpatialValue(inputContext.Version); // Spatial value can be either null constant or a JSON object // If it's a null primitive value, report a null value. if (!insideJsonObjectValue && TryReadNullValue(jsonReader, inputContext, expectedValueTypeReference, validateNullValue, propertyName)) { return(null); } System.Spatial.ISpatial spatialValue = null; if (insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject) { IDictionary <string, object> jsonObject = ReadObjectValue(jsonReader, insideJsonObjectValue, inputContext, recursionDepth); System.Spatial.GeoJsonObjectFormatter jsonObjectFormatter = System.Spatial.SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter(); if (EdmLibraryExtensions.IsGeographyType(expectedValueTypeReference)) { spatialValue = jsonObjectFormatter.Read <System.Spatial.Geography>(jsonObject); } else { spatialValue = jsonObjectFormatter.Read <System.Spatial.Geometry>(jsonObject); } } if (spatialValue == null) { throw new ODataException(ODataErrorStrings.ODataJsonReaderCoreUtils_CannotReadSpatialPropertyValue); } return(spatialValue); }
/// <summary> /// Writes a property with a collection value in ATOM format. /// </summary> /// <param name="collectionValue">The collection value to write.</param> /// <param name="propertyName">The name of the property being written.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingTopLevelCollection">true if writing a top-level collection payload 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="propertyTypeReference">The type reference of the collection value (or null if no metadata is available).</param> /// <param name="isOpenPropertyType">true if this property is undeclared and the owning type is open.</param> private void WriteCollectionValueProperty( ODataCollectionValue collectionValue, string propertyName, bool isTopLevel, bool isWritingTopLevelCollection, Action beforePropertyAction, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType) { ODataVersionChecker.CheckCollectionValueProperties(this.Version, propertyName); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingTopLevelCollection, isTopLevel); this.WriteCollectionValue(collectionValue, propertyTypeReference, isOpenPropertyType, isWritingTopLevelCollection); this.WritePropertyEnd(); }
internal static string ConvertToUriCollectionLiteral(ODataCollectionValue collectionValue, IEdmModel model, ODataVersion version) { ExceptionUtils.CheckArgumentNotNull<ODataCollectionValue>(collectionValue, "collectionValue"); ExceptionUtils.CheckArgumentNotNull<IEdmModel>(model, "model"); ODataVersionChecker.CheckCollectionValue(version); StringBuilder sb = new StringBuilder(); using (TextWriter writer = new StringWriter(sb, CultureInfo.InvariantCulture)) { JsonWriter jsonWriter = new JsonWriter(writer, false); ODataMessageWriterSettings messageWriterSettings = new ODataMessageWriterSettings { Version = new ODataVersion?(version) }; using (ODataJsonOutputContext context = ODataJsonOutputContext.Create(ODataFormat.VerboseJson, jsonWriter, messageWriterSettings, false, model, null)) { new ODataJsonPropertyAndValueSerializer(context).WriteCollectionValue(collectionValue, null, false); } } return sb.ToString(); }
/// <summary> /// Converts a primitive to a string for use in a Url. /// </summary> /// <param name="value">Value to convert.</param> /// <param name="version">OData version to be compliant with.</param> /// <returns>A string representation of <paramref name="value"/> to be added to a Url.</returns> internal static string ConvertToUriPrimitiveLiteral(object value, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(value, "value"); /* This should have the same behavior of Astoria with these differences: (iawillia, 10/7/11) * TODO BUG 292670: Differences between Astoria and ODL's Uri literals * 1) Cannot handle the System.Data.Linq.Binary type * 2) Cannot handle the System.Data.Linq.XElement type * 3) Astoria does not put a 'd' or 'D' on double values */ if (value is ISpatial) { ODataVersionChecker.CheckSpatialValue(version); } // for legacy backwards compatibility reasons, use the formatter which does not URL-encode the resulting string. return(LiteralFormatter.ForConstantsWithoutEncoding.Format(value)); }
/// <summary> /// Converts the given <paramref name="value"/> to a corresponding CLR type. Expects the /// <paramref name="value"/> to have already been properly unescaped from an actual Uri. /// </summary> /// <param name="value">Value from a Uri to be converted.</param> /// <param name="version">Version to be compliant with.</param> /// <param name="model">Optional model to perform verification against.</param> /// <param name="typeReference">Optional IEdmTypeReference to perform verification against. /// Callers must provide a <paramref name="model"/> containing this type if it is specified.</param> /// <returns>A CLR object that the <paramref name="value"/> represents.</returns> public static object ConvertFromUriLiteral(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference) { ExceptionUtils.CheckArgumentNotNull(value, "value"); if (typeReference != null && model == null) { throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralTypeRefWithoutModel); } if (model == null) { model = Microsoft.Data.Edm.Library.EdmCoreModel.Instance; } // Let ExpressionLexer try to get a primitive ExpressionLexer lexer = new ExpressionLexer(value, false /*moveToFirstToken*/, false /*useSemicolonDelimeter*/); Exception error; ExpressionToken token; lexer.TryPeekNextToken(out token, out error); if (token.Kind == ExpressionTokenKind.BracketedExpression) { // Should be a complex or collection value return(ODataUriConversionUtils.ConvertFromComplexOrCollectionValue(value, version, model, typeReference)); } object result = lexer.ReadLiteralToken(); // If we have a typeReference then perform verification and convert if necessary if (typeReference != null) { result = ODataUriConversionUtils.VerifyAndCoerceUriPrimitiveLiteral(result, model, typeReference, version); } if (result is ISpatial) { ODataVersionChecker.CheckSpatialValue(version); } return(result); }
internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version) { ExceptionUtils.CheckArgumentNotNull<object>(primitiveValue, "primitiveValue"); ExceptionUtils.CheckArgumentNotNull<IEdmModel>(model, "model"); ExceptionUtils.CheckArgumentNotNull<IEdmTypeReference>(expectedTypeReference, "expectedTypeReference"); ODataUriNullValue value2 = primitiveValue as ODataUriNullValue; if (value2 != null) { if (!expectedTypeReference.IsNullable) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName())); } IEdmType type = ValidationUtils.ValidateValueTypeName(model, value2.TypeName, expectedTypeReference.Definition.TypeKind); if (type.IsSpatial()) { ODataVersionChecker.CheckSpatialValue(version); } if (!TypePromotionUtils.CanConvertTo(type.ToTypeReference(), expectedTypeReference)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralNullTypeVerificationFailure(expectedTypeReference.ODataFullName(), value2.TypeName)); } value2.TypeName = expectedTypeReference.ODataFullName(); return value2; } IEdmPrimitiveTypeReference reference = expectedTypeReference.AsPrimitiveOrNull(); if (reference == null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue)); } object obj2 = CoerceNumericType(primitiveValue, reference.PrimitiveDefinition()); if (obj2 != null) { return obj2; } Type c = primitiveValue.GetType(); if (!TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(reference)).IsAssignableFrom(c)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(reference.ODataFullName(), primitiveValue)); } return primitiveValue; }
/// <summary> /// Converts a <see cref="ODataCollectionValue"/> to a string for use in a Url. /// </summary> /// <param name="collectionValue">Instance to convert.</param> /// <param name="model">Model to be used for validation. User model is optional. The EdmLib core model is expected as a minimum.</param> /// <param name="version">Version to be compliant with. Collection requires >= V3.</param> /// <returns>A string representation of <paramref name="collectionValue"/> to be added to a Url.</returns> internal static string ConvertToUriCollectionLiteral(ODataCollectionValue collectionValue, IEdmModel model, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(collectionValue, "collectionValue"); ExceptionUtils.CheckArgumentNotNull(model, "model"); ODataVersionChecker.CheckCollectionValue(version); StringBuilder builder = new StringBuilder(); using (TextWriter textWriter = new StringWriter(builder, CultureInfo.InvariantCulture)) { JsonWriter jsonWriter = new JsonWriter(textWriter, false); ODataMessageWriterSettings messageWriterSettings = new ODataMessageWriterSettings() { Version = version }; // Calling dispose since it's the right thing to do, but when created from JsonWriter // the output context Dispose will not actually dispose anything, it will just cleanup itself. using (ODataJsonOutputContext jsonOutputContext = ODataJsonOutputContext.Create( ODataFormat.VerboseJson, jsonWriter, messageWriterSettings, false /*writingResponse*/, model, null /*urlResolver*/)) { ODataJsonPropertyAndValueSerializer jsonPropertyAndValueSerializer = new ODataJsonPropertyAndValueSerializer(jsonOutputContext); jsonPropertyAndValueSerializer.WriteCollectionValue( collectionValue, null, /*propertyTypeRefereence*/ false /*openPropertyType - this determines if the TypeName will be written*/); jsonPropertyAndValueSerializer.AssertRecursionDepthIsZero(); } } return(builder.ToString()); }
/// <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); } } } } }
protected override void EndEntry(ODataEntry entry) { Debug.Assert( this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value, "We should have already verified that the IsCollection matches the actual content of the link (feed/entry)."); if (entry == null) { Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation."); // this is a null expanded single entry and it is null, an empty <m:inline /> will be written. this.CheckAndWriteParentNavigationLinkEndForInlineElement(); return; } IEdmEntityType entryType = this.EntryEntityType; // Initialize the property value cache and cache the entry properties. EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry); // NOTE: when writing, we assume the model has been validated already and thus pass int.MaxValue for the maxMappingCount. ODataEntityPropertyMappingCache epmCache = this.atomOutputContext.Model.EnsureEpmCache(entryType, /*maxMappingCount*/ int.MaxValue); // Populate the property value cache based on the EPM source tree information. // We do this since we need to write custom EPM after the properties below and don't // want to cache all properties just for the case that they are used in a custom EPM. if (epmCache != null) { EpmWriterUtils.CacheEpmProperties(propertyValueCache, epmCache.EpmSourceTree); } // Get the projected properties annotation ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>(); AtomEntryScope currentEntryScope = this.CurrentEntryScope; AtomEntryMetadata entryMetadata = entry.Atom(); if (!currentEntryScope.IsElementWritten(AtomElement.Id)) { // NOTE: We write even null id, in that case we generate an empty atom:id element. this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id); } Uri editLink = entry.EditLink; if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink)) { this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata); } Uri readLink = entry.ReadLink; if (readLink != null && !currentEntryScope.IsElementWritten(AtomElement.ReadLink)) { this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata); } // write entry metadata including syndication EPM AtomEntryMetadata epmEntryMetadata = null; if (epmCache != null) { ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryType, this.atomOutputContext.Model); epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm( epmCache.EpmTargetTree, propertyValueCache, entryType.ToTypeReference().AsEntity(), this.atomOutputContext); } this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime); // stream properties IEnumerable <ODataProperty> streamProperties = propertyValueCache.EntryStreamProperties; if (streamProperties != null) { foreach (ODataProperty streamProperty in streamProperties) { this.atomEntryAndFeedSerializer.WriteStreamProperty( streamProperty, entryType, this.DuplicatePropertyNamesChecker, projectedProperties); } } // association links IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { foreach (ODataAssociationLink associationLink in associationLinks) { this.atomEntryAndFeedSerializer.WriteAssociationLink( associationLink, entryType, this.DuplicatePropertyNamesChecker, projectedProperties); } } // actions IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { foreach (ODataAction action in actions) { ValidationUtils.ValidateOperationNotNull(action, true); this.atomEntryAndFeedSerializer.WriteOperation(action); } } // functions IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { foreach (ODataFunction function in functions) { ValidationUtils.ValidateOperationNotNull(function, false); this.atomEntryAndFeedSerializer.WriteOperation(function); } } // write the content this.WriteEntryContent( entry, entryType, propertyValueCache, epmCache == null ? null : epmCache.EpmSourceTree.Root, projectedProperties); // write custom EPM if (epmCache != null) { EpmCustomWriter.WriteEntryEpm( this.atomOutputContext.XmlWriter, epmCache.EpmTargetTree, propertyValueCache, entryType.ToTypeReference().AsEntity(), this.atomOutputContext); } // </entry> this.atomOutputContext.XmlWriter.WriteEndElement(); this.EndEntryXmlCustomization(entry); this.CheckAndWriteParentNavigationLinkEndForInlineElement(); }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param> /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param> /// <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="version">The protocol version used for writing.</param> /// <param name="isTopLevel">True if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">True if we are writing a collection instead of an entry.</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> internal static void WriteProperty( XmlWriter writer, DataServiceMetadataProviderWrapper metadata, ODataProperty property, ResourceType owningType, ODataVersion version, bool isTopLevel, bool isWritingCollection, EpmValueCache epmValueCache, EpmSourcePathSegment epmParentSourcePathSegment) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); ValidationUtils.ValidateProperty(property); ResourceProperty resourceProperty = ValidationUtils.ValidatePropertyDefined(property.Name, owningType); EpmSourcePathSegment epmSourcePathSegment = null; if (epmParentSourcePathSegment != null) { epmSourcePathSegment = epmParentSourcePathSegment.SubProperties.Where(subProperty => subProperty.PropertyName == property.Name).FirstOrDefault(); } object value = property.Value; // TODO: If we implement validation or 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. // If EPM tells us to skip this property in content, then we're done here. if (!ShouldWritePropertyInContent(value, epmSourcePathSegment, version)) { return; } // <d:propertyname> writer.WriteStartElement( isWritingCollection ? string.Empty : AtomConstants.ODataNamespacePrefix, property.Name, AtomConstants.ODataNamespace); if (isTopLevel) { WriteDefaultNamespaceAttributes(writer, DefaultNamespaceFlags.OData | DefaultNamespaceFlags.ODataMetadata); } // Null property value. if (value == null) { // verify that MultiValue properties are not null if (resourceProperty != null && resourceProperty.Kind == ResourcePropertyKind.MultiValue) { throw new ODataException(Strings.ODataWriter_MultiValuePropertiesMustNotHaveNullValue(resourceProperty.Name)); } ODataAtomWriterUtils.WriteNullAttribute(writer); } else { ODataComplexValue complexValue = value as ODataComplexValue; ResourceType resourcePropertyType = resourceProperty == null ? null : resourceProperty.ResourceType; bool isOpenPropertyType = owningType != null && owningType.IsOpenType && resourceProperty == null; // Complex properties are written recursively. if (complexValue != null) { WriteComplexValue(writer, metadata, complexValue, resourcePropertyType, isOpenPropertyType, isWritingCollection, version, epmValueCache, epmSourcePathSegment); } else { ODataMultiValue multiValue = value as ODataMultiValue; if (multiValue != null) { ODataVersionChecker.CheckMultiValueProperties(version, property.Name); WriteMultiValue(writer, metadata, multiValue, resourcePropertyType, isOpenPropertyType, isWritingCollection, version, epmValueCache, epmSourcePathSegment); } else { WritePrimitiveValue(writer, value, resourcePropertyType); } } } // </d:propertyname> writer.WriteEndElement(); }
/// <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 syndication part of EPM for an entry into ATOM metadata OM. /// </summary> /// <param name="epmTargetTree">The EPM target tree to use.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="resourceType">The resource type of the entry.</param> /// <param name="metadata">The metadata provider to use.</param> /// <param name="version">The version of OData protocol to use.</param> /// <returns>The ATOM metadata OM with the EPM values populated.</returns> internal static AtomEntryMetadata WriteEntryEpm( EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmTargetTree != null, "epmTargetTree != null"); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(resourceType != null, "For any EPM to exist the metadata must be available."); // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = epmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return(null); } AtomEntryMetadata entryMetadata = new AtomEntryMetadata(); foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.IsMultiValueProperty) { Debug.Assert( targetSegment.EpmInfo != null && targetSegment.EpmInfo.Attribute != null, "MultiValue property target segment must have EpmInfo and the Epm Attribute."); ODataVersionChecker.CheckMultiValueProperties(version, targetSegment.EpmInfo.Attribute.SourcePath); // WriteMultiValueEpm(entry, targetSegment, epmValueCache); throw new NotImplementedException(); } else if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the Epm attribute"); bool nullOnParentProperty; object propertyValue = epmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty); string textPropertyValue = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: entryMetadata.Updated = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, version); break; case SyndicationItemProperty.Published: entryMetadata.Published = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, version); break; case SyndicationItemProperty.Rights: entryMetadata.Rights = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Summary: entryMetadata.Summary = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Title: entryMetadata.Title = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } } else if (targetSegment.SegmentName == AtomConstants.AtomAuthorElementName) { AtomPersonMetadata authorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Authors == null, "Found two mappings to author, that is invalid."); if (authorMetadata != null) { entryMetadata.Authors = CreateSinglePersonList(authorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomContributorElementName) { AtomPersonMetadata contributorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Contributors == null, "Found two mappings to contributor, that is invalid."); if (contributorMetadata != null) { entryMetadata.Contributors = CreateSinglePersonList(contributorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomLinkElementName) { AtomLinkMetadata linkMetadata = new AtomLinkMetadata(); //// WriteLinkEpm(entry, targetSegment, epmValueCache); Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to link must be conditional."); linkMetadata.Relation = targetSegment.CriteriaValue; List <AtomLinkMetadata> links; if (entryMetadata.Links == null) { links = new List <AtomLinkMetadata>(); entryMetadata.Links = links; } else { links = entryMetadata.Links as List <AtomLinkMetadata>; Debug.Assert(links != null, "AtomEntryMetadata.Links must be of type List<AtomLinkMetadata> since we create it like that."); } links.Add(linkMetadata); throw new NotImplementedException(); } else if (targetSegment.SegmentName == AtomConstants.AtomCategoryElementName) { AtomCategoryMetadata categoryMetadata = new AtomCategoryMetadata(); //// WriteCategoryEpm(entry, targetSegment, epmValueCache) Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to category must be conditional."); categoryMetadata.Scheme = targetSegment.CriteriaValue; List <AtomCategoryMetadata> categories; if (entryMetadata.Categories == null) { categories = new List <AtomCategoryMetadata>(); entryMetadata.Categories = categories; } else { categories = entryMetadata.Links as List <AtomCategoryMetadata>; Debug.Assert(categories != null, "AtomEntryMetadata.Categories must be of type List<AtomCategoryMetadata> since we create it like that."); } categories.Add(categoryMetadata); throw new NotImplementedException(); } else { throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_TargetSegment)); } } return(entryMetadata); }
protected override void EndEntry(ODataEntry entry) { if (entry == null) { this.CheckAndWriteParentNavigationLinkEndForInlineElement(); } else { IEdmEntityType entryEntityType = base.EntryEntityType; EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry); ODataEntityPropertyMappingCache cache2 = this.atomOutputContext.Model.EnsureEpmCache(entryEntityType, 0x7fffffff); if (cache2 != null) { EpmWriterUtils.CacheEpmProperties(propertyValueCache, cache2.EpmSourceTree); } ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>(); AtomEntryScope currentEntryScope = this.CurrentEntryScope; AtomEntryMetadata entryMetadata = entry.Atom(); if (!currentEntryScope.IsElementWritten(AtomElement.Id)) { this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id); } Uri editLink = entry.EditLink; if ((editLink != null) && !currentEntryScope.IsElementWritten(AtomElement.EditLink)) { this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata); } Uri readLink = entry.ReadLink; if ((readLink != null) && !currentEntryScope.IsElementWritten(AtomElement.ReadLink)) { this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata); } AtomEntryMetadata epmEntryMetadata = null; if (cache2 != null) { ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryEntityType, this.atomOutputContext.Model); epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm(cache2.EpmTargetTree, propertyValueCache, entryEntityType.ToTypeReference().AsEntity(), this.atomOutputContext); } this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime); IEnumerable <ODataProperty> entryStreamProperties = propertyValueCache.EntryStreamProperties; if (entryStreamProperties != null) { foreach (ODataProperty property in entryStreamProperties) { this.atomEntryAndFeedSerializer.WriteStreamProperty(property, entryEntityType, base.DuplicatePropertyNamesChecker, projectedProperties); } } IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { foreach (ODataAssociationLink link in associationLinks) { this.atomEntryAndFeedSerializer.WriteAssociationLink(link, entryEntityType, base.DuplicatePropertyNamesChecker, projectedProperties); } } IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { foreach (ODataAction action in actions) { ValidationUtils.ValidateOperationNotNull(action, true); this.atomEntryAndFeedSerializer.WriteOperation(action); } } IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { foreach (ODataFunction function in functions) { ValidationUtils.ValidateOperationNotNull(function, false); this.atomEntryAndFeedSerializer.WriteOperation(function); } } this.WriteEntryContent(entry, entryEntityType, propertyValueCache, (cache2 == null) ? null : cache2.EpmSourceTree.Root, projectedProperties); if (cache2 != null) { EpmCustomWriter.WriteEntryEpm(this.atomOutputContext.XmlWriter, cache2.EpmTargetTree, propertyValueCache, entryEntityType.ToTypeReference().AsEntity(), this.atomOutputContext); } this.atomOutputContext.XmlWriter.WriteEndElement(); this.EndEntryXmlCustomization(entry); this.CheckAndWriteParentNavigationLinkEndForInlineElement(); } }
/// <summary> /// Reads a collection value. /// </summary> /// <param name="collectionValueTypeReference">The collection type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <returns>The value of the collection.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject /// Post-Condition: almost anything - the node after the collection value (after the EndObject) /// </remarks> private ODataCollectionValue ReadCollectionValueImplementation( IEdmCollectionTypeReference collectionValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert( collectionValueTypeReference == null || collectionValueTypeReference.IsNonEntityCollectionType(), "If the metadata is specified it must denote a Collection for this method to work."); this.JsonReader.AssertNotBuffering(); ODataVersionChecker.CheckCollectionValue(this.Version); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataCollectionValue collectionValue = new ODataCollectionValue(); collectionValue.TypeName = collectionValueTypeReference != null?collectionValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { collectionValue.SetAnnotation(serializationTypeNameAnnotation); } List <object> items = null; bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property if (metadataPropertyFound) { throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper(JsonConstants.ODataMetadataName)); } metadataPropertyFound = true; // Note that we don't need to read the type name again, as we've already read it above in FindTypeNameInPayload. // There's nothing else of interest in the __metadata for collections. this.JsonReader.SkipValue(); } else if (string.CompareOrdinal(JsonConstants.ODataResultsName, propertyName) == 0) { // results property if (items != null) { throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper(JsonConstants.ODataResultsName)); } items = new List <object>(); this.JsonReader.ReadStartArray(); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); IEdmTypeReference itemType = null; if (collectionValueTypeReference != null) { itemType = collectionValueTypeReference.CollectionDefinition().ElementType; } // NOTE: we do not support reading Verbose JSON without metadata right now so we always have an expected item type; // The collection validator is always null. CollectionWithoutExpectedTypeValidator collectionValidator = null; while (this.JsonReader.NodeType != JsonNodeType.EndArray) { object itemValue = this.ReadNonEntityValueImplementation( itemType, duplicatePropertyNamesChecker, collectionValidator, /*validateNullValue*/ true, /*propertyName*/ null); // Validate the item (for example that it's not null) ValidationUtils.ValidateCollectionItem(itemValue, false /* isStreamable */); // Note that the ReadNonEntityValue already validated that the actual type of the value matches // the expected type (the itemType). items.Add(itemValue); } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndArray, "The results value must end with an end array."); this.JsonReader.ReadEndArray(); } else { // Skip over any other property in the collection object this.JsonReader.SkipValue(); } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all properties of Collection wrapper are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); if (items == null) { // We didn't find any results property. All collections must have the results property. throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_CollectionWithoutResults); } collectionValue.Items = new ReadOnlyEnumerable(items); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return(collectionValue); }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); bool shouldWriteRawAnnotations = false; if (!ShouldWriteProperty(owningType, property, edmProperty, out shouldWriteRawAnnotations)) { return; } IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; bool alreadyWroteODataType = false; if (shouldWriteRawAnnotations) { TryWriteRawAnnotations(property, out alreadyWroteODataType); } // handle ODataUntypedValue ODataUntypedValue untypedValue = property.Value as ODataUntypedValue; if (untypedValue != null) { if (this.MessageWriterSettings.ContainUndeclaredPropertyBehavior( ODataUndeclaredPropertyBehaviorKinds.SupportUndeclaredValueProperty)) { this.JsonWriter.WriteName(propertyName); this.JsonWriter.WriteRawString(untypedValue.RawJson); } return; } ODataValue value = property.ODataValue; ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; // 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. bool isSpatial = (propertyTypeReference != null && propertyTypeReference.IsSpatial()) || (propertyTypeReference == null && primitiveValue != null && primitiveValue.Value is ISpatial); if (isSpatial) { ODataVersionChecker.CheckSpatialValue(this.Version); } 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.Version, this.WritingResponse); 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); if (isTopLevel) { // Write the special null marker for top-level null properties. this.JsonWriter.WriteName(ODataAnnotationNames.ODataNull); this.JsonWriter.WriteValue(true); } else { this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteNullValue(); } return; } bool isOpenPropertyType = IsOpenPropertyType(property, owningType, edmProperty); if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); } 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); ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { if (!alreadyWroteODataType) { string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel); } this.JsonWriter.WriteName(wirePropertyName); ODataVersionChecker.CheckCollectionValueProperties(this.Version, propertyName); // passing false for 'isTopLevel' because the outer wrapping object has already been written. this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType); return; } Debug.Assert(primitiveValue != null, "primitiveValue != null"); if (!alreadyWroteODataType) { 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); }
internal static string ConvertToUriPrimitiveLiteral(object value, ODataVersion version) { ExceptionUtils.CheckArgumentNotNull<object>(value, "value"); StringBuilder builder = new StringBuilder(); Type nullableType = value.GetType(); nullableType = Nullable.GetUnderlyingType(nullableType) ?? nullableType; switch (Microsoft.Data.OData.PlatformHelper.GetTypeCode(nullableType)) { case TypeCode.Object: if (!(nullableType == typeof(byte[]))) { if (nullableType == typeof(Guid)) { builder.Append("guid"); builder.Append("'"); builder.Append(value.ToString()); builder.Append("'"); } else if (nullableType == typeof(DateTimeOffset)) { builder.Append("datetimeoffset"); builder.Append("'"); builder.Append(XmlConvert.ToString((DateTimeOffset) value)); builder.Append("'"); } else if (nullableType == typeof(TimeSpan)) { builder.Append("time"); builder.Append("'"); builder.Append(XmlConvert.ToString((TimeSpan) value)); builder.Append("'"); } else if (typeof(Geography).IsAssignableFrom(nullableType)) { ODataVersionChecker.CheckSpatialValue(version); builder.Append("geography"); builder.Append("'"); builder.Append(WellKnownTextSqlFormatter.Create(true).Write((Geography) value)); builder.Append("'"); } else { if (!typeof(Geometry).IsAssignableFrom(nullableType)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertToUriLiteralUnsupportedType(nullableType.ToString())); } ODataVersionChecker.CheckSpatialValue(version); builder.Append("geometry"); builder.Append("'"); builder.Append(WellKnownTextSqlFormatter.Create(true).Write((Geometry) value)); builder.Append("'"); } break; } builder.Append(ConvertByteArrayToKeyString((byte[]) value)); break; case TypeCode.Boolean: builder.Append(XmlConvert.ToString((bool) value)); return builder.ToString(); case TypeCode.SByte: builder.Append(XmlConvert.ToString((sbyte) value)); return builder.ToString(); case TypeCode.Byte: builder.Append(XmlConvert.ToString((byte) value)); return builder.ToString(); case TypeCode.Int16: builder.Append(XmlConvert.ToString((short) value)); return builder.ToString(); case TypeCode.Int32: builder.Append(XmlConvert.ToString((int) value)); return builder.ToString(); case TypeCode.Int64: builder.Append(XmlConvert.ToString((long) value)); builder.Append("L"); return builder.ToString(); case TypeCode.Single: builder.Append(XmlConvert.ToString((float) value)); builder.Append("f"); return builder.ToString(); case TypeCode.Double: builder.Append(AppendDecimalMarkerToDouble(XmlConvert.ToString((double) value))); builder.Append("D"); return builder.ToString(); case TypeCode.Decimal: builder.Append(XmlConvert.ToString((decimal) value)); builder.Append("M"); return builder.ToString(); case TypeCode.DateTime: builder.Append("datetime"); builder.Append("'"); builder.Append(Microsoft.Data.OData.PlatformHelper.ConvertDateTimeToString((DateTime) value)); builder.Append("'"); return builder.ToString(); case TypeCode.String: builder.Append("'"); builder.Append(((string) value).Replace("'", "''")); builder.Append("'"); return builder.ToString(); default: throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertToUriLiteralUnsupportedType(nullableType.ToString())); } return builder.ToString(); }
private ODataCollectionValue ReadCollectionValueImplementation(IEdmCollectionTypeReference collectionValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation) { ODataVersionChecker.CheckCollectionValue(base.Version); this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataCollectionValue value2 = new ODataCollectionValue { TypeName = (collectionValueTypeReference != null) ? collectionValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } List <object> sourceEnumerable = null; bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper("__metadata")); } flag = true; base.JsonReader.SkipValue(); } else { if (string.CompareOrdinal("results", strB) == 0) { if (sourceEnumerable != null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper("results")); } sourceEnumerable = new List <object>(); base.JsonReader.ReadStartArray(); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); IEdmTypeReference expectedTypeReference = null; if (collectionValueTypeReference != null) { expectedTypeReference = collectionValueTypeReference.CollectionDefinition().ElementType; } CollectionWithoutExpectedTypeValidator collectionValidator = null; while (base.JsonReader.NodeType != JsonNodeType.EndArray) { object item = this.ReadNonEntityValueImplementation(expectedTypeReference, duplicatePropertyNamesChecker, collectionValidator, true); ValidationUtils.ValidateCollectionItem(item, false); sourceEnumerable.Add(item); } base.JsonReader.ReadEndArray(); continue; } base.JsonReader.SkipValue(); } } base.JsonReader.ReadEndObject(); if (sourceEnumerable == null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CollectionWithoutResults); } value2.Items = new ReadOnlyEnumerable(sourceEnumerable); this.DecreaseRecursionDepth(); return(value2); }
/// <summary> /// Converts a primitive to a string for use in a Url. /// </summary> /// <param name="value">Value to convert.</param> /// <param name="version">OData version to be compliant with.</param> /// <returns>A string representation of <paramref name="value"/> to be added to a Url.</returns> internal static string ConvertToUriPrimitiveLiteral(object value, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(value, "value"); /* This should have the same behavior of Astoria with these differences: (iawillia, 10/7/11) * TODO BUG 292670: Differences betwen Astoria and ODL's Uri literals * 1) Cannot handle the System.Data.Linq.Binary type * 2) Cannot handle the System.Data.Linq.XElement type * 3) Astoria does not put a 'd' or 'D' on double values */ StringBuilder builder = new StringBuilder(); Type valueType = value.GetType(); valueType = Nullable.GetUnderlyingType(valueType) ?? valueType; TypeCode code = o.PlatformHelper.GetTypeCode(valueType); switch (code) { case TypeCode.Boolean: builder.Append(XmlConvert.ToString((bool)value)); return(builder.ToString()); case TypeCode.Byte: builder.Append(XmlConvert.ToString((byte)value)); return(builder.ToString()); case TypeCode.DateTime: builder.Append(ExpressionConstants.LiteralPrefixDateTime); builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(o.PlatformHelper.ConvertDateTimeToString((DateTime)value)); builder.Append(ExpressionConstants.LiteralSingleQuote); return(builder.ToString()); case TypeCode.Decimal: builder.Append(XmlConvert.ToString((Decimal)value)); builder.Append(ExpressionConstants.LiteralSuffixDecimal); return(builder.ToString()); case TypeCode.Double: builder.Append(AppendDecimalMarkerToDouble(XmlConvert.ToString((Double)value))); builder.Append(ExpressionConstants.LiteralSuffixDouble); return(builder.ToString()); case TypeCode.Int16: builder.Append(XmlConvert.ToString((Int16)value)); return(builder.ToString()); case TypeCode.Int32: builder.Append(XmlConvert.ToString((Int32)value)); return(builder.ToString()); case TypeCode.Int64: builder.Append(XmlConvert.ToString((Int64)value)); builder.Append(ExpressionConstants.LiteralSuffixInt64); return(builder.ToString()); case TypeCode.Object: if (valueType == typeof(byte[])) { builder.Append(ConvertByteArrayToKeyString((byte[])value)); } else if (valueType == typeof(Guid)) { builder.Append(ExpressionConstants.LiteralPrefixGuid); builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(value.ToString()); builder.Append(ExpressionConstants.LiteralSingleQuote); } else if (valueType == typeof(DateTimeOffset)) { builder.Append(ExpressionConstants.LiteralPrefixDateTimeOffset); builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(XmlConvert.ToString((DateTimeOffset)value)); builder.Append(ExpressionConstants.LiteralSingleQuote); } else if (valueType == typeof(TimeSpan)) { builder.Append(ExpressionConstants.LiteralPrefixTime); builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(XmlConvert.ToString((TimeSpan)value)); builder.Append(ExpressionConstants.LiteralSingleQuote); } else if (typeof(Geography).IsAssignableFrom(valueType)) { ODataVersionChecker.CheckSpatialValue(version); builder.Append(ExpressionConstants.LiteralPrefixGeography); builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(WellKnownTextSqlFormatter.Create(true).Write((Geography)value)); builder.Append(ExpressionConstants.LiteralSingleQuote); } else if (typeof(Geometry).IsAssignableFrom(valueType)) { ODataVersionChecker.CheckSpatialValue(version); builder.Append(ExpressionConstants.LiteralPrefixGeometry); builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(WellKnownTextSqlFormatter.Create(true).Write((Geometry)value)); builder.Append(ExpressionConstants.LiteralSingleQuote); } else { throw new ODataException(o.Strings.ODataUriUtils_ConvertToUriLiteralUnsupportedType(valueType.ToString())); } return(builder.ToString()); case TypeCode.SByte: builder.Append(XmlConvert.ToString((SByte)value)); return(builder.ToString()); case TypeCode.Single: builder.Append(XmlConvert.ToString((Single)value)); builder.Append(ExpressionConstants.LiteralSuffixSingle); return(builder.ToString()); case TypeCode.String: builder.Append(ExpressionConstants.LiteralSingleQuote); builder.Append(((String)value).Replace("'", "''")); builder.Append(ExpressionConstants.LiteralSingleQuote); return(builder.ToString()); default: throw new ODataException(o.Strings.ODataUriUtils_ConvertToUriLiteralUnsupportedType(valueType.ToString())); } }
/// <summary> /// Finish writing an entry. /// </summary> /// <param name="entry">The entry to write.</param> protected override void EndEntry(ODataEntry entry) { Debug.Assert(entry != null, "entry != null"); string typeName = entry.TypeName; ResourceType entryType = ValidationUtils.ValidateTypeName(this.MetadataProvider, typeName, ResourceTypeKind.EntityType, false); // Initialize the property value cache and cache the entry properties. EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry); EpmResourceTypeAnnotation epmResourceTypeAnnotation = null; if (entryType != null) { Debug.Assert(entryType.IsReadOnly, "The resource must be read-only to be applied to an entry."); entryType.EnsureEpmAvailability(); epmResourceTypeAnnotation = entryType.Epm(); } // <atom:id>idValue</atom:id> // NOTE: do not generate a relative Uri for the ID; it is independent of xml:base ODataAtomWriterUtils.WriteElementWithTextContent( this.writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIdElementName, AtomConstants.AtomNamespace, entry.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 happened at the beginning of this method. if (typeName != null) { ODataAtomWriterMetadataUtils.WriteCategory(this.writer, typeName, AtomConstants.ODataSchemeNamespace, null); } Uri editLink = entry.EditLink; if (editLink != null) { // <link rel="edit" title="Title" href="LinkHRef"/> ODataAtomWriterUtils.WriteReadOrEditLink(this.writer, this.BaseUri, editLink, AtomConstants.AtomEditRelationAttributeValue, typeName); } Uri readLink = entry.ReadLink; if (readLink != null) { // <link rel="self" title="Title" href="LinkHRef"/> ODataAtomWriterUtils.WriteReadOrEditLink(this.writer, this.BaseUri, readLink, AtomConstants.AtomSelfRelationAttributeValue, typeName); } // named streams IEnumerable <ODataMediaResource> namedStreams = entry.NamedStreams; if (namedStreams != null) { foreach (ODataMediaResource namedStream in namedStreams) { ValidationUtils.ValidateNamedStream(namedStream, this.Version); ODataAtomWriterUtils.WriteNamedStream(this.writer, this.BaseUri, namedStream); } } // association links IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { foreach (ODataAssociationLink associationLink in associationLinks) { ValidationUtils.ValidateAssociationLink(associationLink, this.Version); ODataAtomWriterUtils.WriteAssociationLink(this.writer, this.BaseUri, entry, associationLink); } } // write entry metadata including syndication EPM AtomEntryMetadata epmEntryMetadata = null; if (epmResourceTypeAnnotation != null) { ODataVersionChecker.CheckEntityPropertyMapping(this.Version, entryType); epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm( epmResourceTypeAnnotation.EpmTargetTree, propertyValueCache, entryType, this.MetadataProvider, this.Version); } ODataAtomWriterMetadataUtils.WriteEntryMetadata(this.writer, this.BaseUri, entry, epmEntryMetadata); // write the content this.WriteEntryContent(entry, entryType, propertyValueCache, epmResourceTypeAnnotation == null ? null : epmResourceTypeAnnotation.EpmSourceTree.Root); // write custom EPM if (epmResourceTypeAnnotation != null) { EpmCustomWriter.WriteEntryEpm( this.writer, epmResourceTypeAnnotation.EpmTargetTree, propertyValueCache, entryType, this.MetadataProvider); } // </entry> this.writer.WriteEndElement(); }
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); }
/// <summary> /// Writes a single property in ATOM format. /// </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="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a 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.EmptyProjectedPropertiesMarker; } else { return(false); } } WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); if (value is ODataStreamReferenceValue) { throw new ODataException(o.Strings.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 ((edmProperty != null && edmProperty.Type.IsSpatial()) || (edmProperty == null && value is System.Spatial.ISpatial)) { ODataVersionChecker.CheckSpatialValue(this.Version); } // Null property value. if (value == null) { this.WriteNullPropertyValue(edmProperty, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = owningType != null && owningType.IsOpen && edmProperty == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (complexValue != null) { // Complex properties are written recursively. DuplicatePropertyNamesChecker complexValuePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); if (isTopLevel) { // Top-level property must always write the property element Debug.Assert(complexValueProjectedProperties == null, "complexValueProjectedProperties == null"); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.AssertRecursionDepthIsZero(); this.WriteComplexValue( complexValue, propertyTypeReference, isOpenPropertyType, isWritingCollection, null /* beforeValueAction */, null /* afterValueAction */, complexValuePropertyNamesChecker, null /* collectionValidator */, epmValueCache, epmSourcePathSegment, null /* projectedProperties */); this.AssertRecursionDepthIsZero(); this.WritePropertyEnd(); return(true); } return(this.WriteComplexValue( complexValue, propertyTypeReference, isOpenPropertyType, isWritingCollection, () => this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel), () => this.WritePropertyEnd(), complexValuePropertyNamesChecker, null /* collectionValidator */, epmValueCache, epmSourcePathSegment, complexValueProjectedProperties)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(this.Version, propertyName); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WriteCollectionValue( collectionValue, propertyTypeReference, isOpenPropertyType, isWritingCollection); this.WritePropertyEnd(); return(true); } this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference); this.WritePropertyEnd(); return(true); }