/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { return null; }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { SerializationTypeNameAnnotation typeNameAnnotation = value.GetAnnotation<SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return typeNameAnnotation.TypeName; } if (typeReferenceFromValue != null) { // Write type name when the type in the payload is more derived than the type from metadata. if (typeReferenceFromMetadata != null && typeReferenceFromMetadata.Definition.AsActualType().ODataFullName() != typeReferenceFromValue.ODataFullName()) { return typeReferenceFromValue.ODataFullName(); } // Note: When writing derived complexType value in a payload, we don't have the expected type. // So always write @odata.type for top-level derived complextype. if (typeReferenceFromMetadata == null && typeReferenceFromValue.IsComplex()) { if ((typeReferenceFromValue as IEdmComplexTypeReference).ComplexDefinition().BaseType != null) { return typeReferenceFromValue.ODataFullName(); } } // Do not write type name when the type is native json type. if (typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return null; } } if (!isOpenProperty) { // Do not write type name for non-open properties since we expect the reader to have an expected type (via API or context URI) and thus not need it. return null; } return GetTypeNameFromValue(value); }
/// <summary> /// Converts an object to an ODataValue. If the given object is already an ODataValue (such as an ODataCompleValue, ODataCollectionValue, etc.), the original object will be returned. /// </summary> /// <param name="objectToConvert">The object to convert to an ODataValue</param> /// <returns>The given object as an ODataValue.</returns> internal static ODataValue ToODataValue(this object objectToConvert) { if (objectToConvert == null) { return(new ODataNullValue()); } // If the given object is already an ODataValue, return it as is. ODataValue odataValue = objectToConvert as ODataValue; if (odataValue != null) { return(odataValue); } // Otherwise treat it as a primitive and wrap in an ODataPrimitiveValue. This includes spatial types. return(new ODataPrimitiveValue(objectToConvert)); }
public void CreateODataValue_ReturnsDateTimeOffset_ForDateTime_ByDefault() { // Arrange IEdmPrimitiveTypeReference edmPrimitiveType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(DateTime)); ODataPrimitiveSerializer serializer = new ODataPrimitiveSerializer(); DateTime dt = new DateTime(2014, 10, 27); TimeZoneInfoHelper.TimeZone = null; // Act ODataValue odataValue = serializer.CreateODataValue(dt, edmPrimitiveType, new ODataSerializerContext()); // Assert ODataPrimitiveValue primitiveValue = Assert.IsType <ODataPrimitiveValue>(odataValue); Assert.Equal(new DateTimeOffset(dt), primitiveValue.Value); }
/// <summary> /// Converts an ODataValue to the old style of representing values, where null values are null and primitive values are just the direct primitive (no longer wrapped by ODataPrimitiveValue). /// All other value types, such as ODataComplexValue and ODataCollectionValue are returned unchanged. /// </summary> /// <param name="odataValue">The value to convert.</param> /// <returns>The value behind the given ODataValue.</returns> internal static object FromODataValue(this ODataValue odataValue) { DebugUtils.CheckNoExternalCallers(); if (odataValue is ODataNullValue) { return(null); } ODataPrimitiveValue primitiveValue = odataValue as ODataPrimitiveValue; if (primitiveValue != null) { return(primitiveValue.Value); } return(odataValue); }
private static JToken SerializeODataValue(ODataValue oDataValue) { if (oDataValue is ODataPrimitiveValue pv) { return(JToken.FromObject(pv.Value)); } if (oDataValue is ODataCollectionValue cv) { return(JArray.FromObject(cv.Items)); } if (oDataValue is ODataUntypedValue ut) { return(JToken.Parse(ut.RawValue)); } throw new InvalidOperationException($"Serializing the odata type {oDataValue.TypeAnnotation.TypeName} is not supported for error data serialization"); }
public void CreateODataValue_Retruns_CorrectODataValue() { // Arrange ODataSerializerContext writeContext = new ODataSerializerContext(); ODataSerializerProvider provider = new Mock <ODataSerializerProvider>().Object; Mock <ODataEnumSerializer> serializer = new Mock <ODataEnumSerializer>(provider); ODataEnumValue enumValue = new ODataEnumValue("Cartoon"); serializer.Setup(s => s.CreateODataEnumValue(null, It.IsAny <IEdmEnumTypeReference>(), writeContext)).Returns(enumValue); IEdmEnumType enumType = new EdmEnumType("NS", "Enum"); IEdmTypeReference expectedType = new EdmEnumTypeReference(enumType, false); // Act ODataValue actual = serializer.Object.CreateODataValue(graph: null, expectedType: expectedType, writeContext); // Assert Assert.Same(enumValue, actual); }
public void CreateODataValue_Calls_CreateODataComplexValue() { // Arrange var oDataComplexValue = new ODataComplexValue(); var complexObject = new object(); Mock <ODataComplexTypeSerializer> serializer = new Mock <ODataComplexTypeSerializer>(new DefaultODataSerializerProvider()); serializer.CallBase = true; serializer .Setup(s => s.CreateODataComplexValue(complexObject, _addressTypeRef, It.IsAny <ODataSerializerContext>())) .Returns(oDataComplexValue) .Verifiable(); // Act ODataValue value = serializer.Object.CreateODataValue(complexObject, _addressTypeRef, new ODataSerializerContext()); // Assert serializer.Verify(); Assert.Same(oDataComplexValue, value); }
public void CreateODataCollectionValue_SetsTypeName() { // Arrange IEnumerable enumerable = new int[] { 1, 2, 3 }; ODataSerializerContext context = new ODataSerializerContext { Model = EdmCoreModel.Instance }; Mock <ODataSerializerProvider> serializerProvider = new Mock <ODataSerializerProvider>(); serializerProvider.Setup(s => s.GetEdmTypeSerializer(It.IsAny <IEdmTypeReference>())).Returns(new ODataPrimitiveSerializer()); ODataCollectionSerializer serializer = new ODataCollectionSerializer(serializerProvider.Object); // Act ODataValue oDataValue = serializer.CreateODataCollectionValue(enumerable, _edmIntType, context); // Assert ODataCollectionValue collection = Assert.IsType <ODataCollectionValue>(oDataValue); Assert.Equal("Collection(Edm.Int32)", collection.TypeName); }
public void BadCustomAnnotationOnErrorWithVerboseErrorsCausesInStreamErrorInErrorPayload() { using (TestWebRequest webRequest = this.SetupRequest()) using (ModifyErrorMessageInHandleExceptionService.UseVerboseErrors.Restore()) using (TestUtil.MetadataCacheCleaner()) { webRequest.Accept = "application/json;odata.metadata=minimal"; ModifyErrorMessageInHandleExceptionService.UseVerboseErrors.Value = true; AnnotationValue = new ODataCollectionValue { Items = new[] { "item1", new object() } }; // the new object is not a supported primitive type. TestUtil.RunCatching(webRequest.SendRequest); // With verbose error, the in-stream error response shows inner exception call stack const string expected = "{\"error\":{\"code\":\"\",\"message\":\"Resource not found for the segment 'ThisDoesNotExist'.\",\"@location.error\":[\"item1\"{\"error\":{\"code\":\"500\",\"message\":\"An error occurred while trying to write an error payload.\",\"innererror\":{\"message\":\"The value of type 'System.Object' is not supported and cannot be converted to a JSON representation.\""; webRequest.ErrorResponseContent.Should().StartWith(expected); HandleExceptionCalls.Should().Be(1); } }
public void CreateODataValue_Calls_CreateODataCollectionValue() { // Arrange ODataCollectionValue oDataCollectionValue = new ODataCollectionValue(); var collection = new object[0]; Mock <ODataCollectionSerializer> serializer = new Mock <ODataCollectionSerializer>(new DefaultODataSerializerProvider()); ODataSerializerContext writeContext = new ODataSerializerContext(); serializer.CallBase = true; serializer .Setup(s => s.CreateODataCollectionValue(collection, _edmIntType, writeContext)) .Returns(oDataCollectionValue) .Verifiable(); // Act ODataValue value = serializer.Object.CreateODataValue(collection, _collectionType, writeContext); // Assert serializer.Verify(); Assert.Same(oDataCollectionValue, value); }
public ODataResource CreateEntry(Object entity) { var odataProperties = new ODataProperty[Accessors.Length]; for (int i = 0; i < Accessors.Length; i++) { Object value = Accessors[i].GetValue(entity); ODataValue odataValue = OeEdmClrHelper.CreateODataValue(value); odataValue.TypeAnnotation = Accessors[i].TypeAnnotation; odataProperties[i] = new ODataProperty() { Name = Accessors[i].EdmProperty.Name, Value = odataValue }; } return(new ODataResource { TypeName = _typeName, Properties = odataProperties }); }
public ODataResource CreateEntry(Object entity) { for (int i = 0; i < _accessors.Length; i++) { OePropertyAccessor accessor = _accessors[i]; Object value = accessor.Accessor(entity); if (value is DateTime) { value = (DateTimeOffset)(DateTime)value; } ODataValue odataValue = null; if (value == null) { odataValue = new ODataNullValue() { TypeAnnotation = accessor.TypeAnnotation } } ; else { if (value.GetType().GetTypeInfo().IsEnum) { odataValue = new ODataEnumValue(value.ToString()); } else { odataValue = new ODataPrimitiveValue(value); } odataValue.TypeAnnotation = accessor.TypeAnnotation; } _odataProperties[i].Value = odataValue; } return(new ODataResource { TypeName = _typeName, Properties = _odataProperties }); }
public static void AssertODataValueAreEqual(ODataValue value1, ODataValue value2) { if (value1.IsNullValue && value2.IsNullValue) { return; } ODataPrimitiveValue primitiveValue1 = value1 as ODataPrimitiveValue; ODataPrimitiveValue primitiveValue2 = value2 as ODataPrimitiveValue; if (primitiveValue1 != null && primitiveValue2 != null) { AssertODataPrimitiveValueAreEqual(primitiveValue1, primitiveValue2); } else { ODataEnumValue enumValue1 = value1 as ODataEnumValue; ODataEnumValue enumValue2 = value2 as ODataEnumValue; if (enumValue1 != null && enumValue2 != null) { AssertODataEnumValueAreEqual(enumValue1, enumValue2); } else { ODataCollectionValue collectionValue1 = value1 as ODataCollectionValue; ODataCollectionValue collectionValue2 = value2 as ODataCollectionValue; if (collectionValue1 != null && collectionValue2 != null) { AssertODataCollectionValueAreEqual(collectionValue1, collectionValue2); } else { ODataUntypedValue untyped1 = value1 as ODataUntypedValue; ODataUntypedValue untyped2 = value2 as ODataUntypedValue; Assert.Equal(untyped1.RawValue, untyped2.RawValue); } } } }
public static void AssertODataValueAreEqual(ODataValue value1, ODataValue value2) { if (value1.IsNullValue && value2.IsNullValue) { return; } ODataPrimitiveValue primitiveValue1 = value1 as ODataPrimitiveValue; ODataPrimitiveValue primitiveValue2 = value2 as ODataPrimitiveValue; if (primitiveValue1 != null && primitiveValue2 != null) { AssertODataPrimitiveValueAreEqual(primitiveValue1, primitiveValue2); } else { ODataComplexValue complexValue1 = value1 as ODataComplexValue; ODataComplexValue complexValue2 = value2 as ODataComplexValue; if (complexValue1 != null && complexValue2 != null) { AssertODataComplexValueAreEqual(complexValue1, complexValue2); } else { ODataEnumValue enumValue1 = value1 as ODataEnumValue; ODataEnumValue enumValue2 = value2 as ODataEnumValue; if (enumValue1 != null && enumValue2 != null) { AssertODataEnumValueAreEqual(enumValue1, enumValue2); } else { ODataCollectionValue collectionValue1 = (ODataCollectionValue)value1; ODataCollectionValue collectionValue2 = (ODataCollectionValue)value2; AssertODataCollectionValueAreEqual(collectionValue1, collectionValue2); } } } }
public void FailedTopLevelBatchRequestShouldBeXmlRegardlessOfCustomAnnotation() { StringBuilder batchQueryOperation = new StringBuilder(); batchQueryOperation.AppendLine("GET Customers(1)/Address?Override-Accept=" + UnitTestsUtil.JsonLightMimeType + " HTTP/1.1"); batchQueryOperation.AppendLine("Host: host"); batchQueryOperation.AppendLine("Accept: " + "application/json;odata.metadata=minimal"); var test = new SimpleBatchTestCase { RequestPayload = new BatchInfo(new BatchQuery(new Operation(batchQueryOperation.ToString()))), ResponseStatusCode = 400, }; using (TestWebRequest webRequest = this.SetupRequest()) { webRequest.HttpMethod = "POST"; webRequest.RequestUriString = "/$batch"; webRequest.Accept = UnitTestsUtil.MimeMultipartMixed; webRequest.RequestVersion = "4.0;"; webRequest.RequestMaxVersion = "4.0;"; webRequest.ForceVerboseErrors = true; const string boundary = "batch-set"; // set content type to json so the batch request fails with 400 webRequest.RequestContentType = String.Format("{0}; boundary={1}", "application/json;odata.metadata=minimal", boundary); webRequest.SetRequestStreamAsText(BatchRequestWritingUtils.GetBatchText(test.RequestPayload, boundary)); AnnotationValue = new ODataPrimitiveValue("This is a custom value message"); TestUtil.RunCatching(webRequest.SendRequest); // Since the error response of top level batch request is xml, the custom error annotation will be ignored webRequest.ResponseStatusCode.Should().Be(test.ResponseStatusCode); webRequest.GetResponseStreamAsText().Should().NotContain("custom value message"); HandleExceptionCalls.Should().Be(1); } }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { SerializationTypeNameAnnotation typeNameAnnotation = value.GetAnnotation<SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return typeNameAnnotation.TypeName; } // Do not write type name when the type is native json type. if (typeReferenceFromValue != null && typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return null; } return GetTypeNameFromValue(value); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { DebugUtils.CheckNoExternalCallers(); SerializationTypeNameAnnotation typeNameAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return(typeNameAnnotation.TypeName); } if (typeReferenceFromValue != null) { // Write type name when the type in the payload is more derived than the type from metadata. if (typeReferenceFromMetadata != null && typeReferenceFromMetadata.ODataFullName() != typeReferenceFromValue.ODataFullName()) { return(typeReferenceFromValue.ODataFullName()); } // Do not write type name when the type is native json type. if (typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } } if (!isOpenProperty) { // Do not write type name for non-open properties since we expect the reader to have an expected type (via API or metadata URI) and thus not need it. return(null); } return(GetTypeNameFromValue(value)); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { SerializationTypeNameAnnotation typeNameAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return(typeNameAnnotation.TypeName); } // Do not write type name when the type is native json type. if (typeReferenceFromValue != null && typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } return(GetTypeNameFromValue(value)); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { string typeNameToWrite; if (TypeNameOracle.TryGetTypeNameFromAnnotation(value, out typeNameToWrite)) { return(typeNameToWrite); } // Do not write type name when the type is native json type. if (typeReferenceFromValue != null && typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } return(GetTypeNameFromValue(value)); }
internal void SetTypeName(ODataValue value, ResourceType actualType) { Debug.Assert(value != null, "value != null"); #if DEBUG var complexValue = value as ODataComplexValue; if (complexValue != null) { Debug.Assert(!String.IsNullOrEmpty(complexValue.TypeName), "Type name must be specified in ODataComplexValue since ODL needs it for validation."); } else { var collectionValue = value as ODataCollectionValue; Debug.Assert(collectionValue == null || !String.IsNullOrEmpty(collectionValue.TypeName), "Type name must be specified in ODataCollectionValue since ODL needs it for validation."); } #endif string typeNameToWrite; if (this.interpreter.ShouldSpecifyTypeNameAnnotation(value, actualType, out typeNameToWrite)) { value.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = typeNameToWrite }); } }
public void ComplexCustomAnnotationOnErrorShouldGetWrittenInJsonLight() { using (TestWebRequest webRequest = this.SetupRequest()) { webRequest.Accept = "application/json;odata.metadata=minimal"; AnnotationValue = new ODataComplexValue { TypeName = "AstoriaUnitTests.Stubs.Address", Properties = new[] { new ODataProperty { Name = "City", Value = "Troy" }, new ODataProperty { Name = "State", Value = "New York" } } }; TestUtil.RunCatching(webRequest.SendRequest); webRequest.ErrorResponseContent.Should().Be("{\"error\":{\"code\":\"\",\"message\":\"Resource not found for the segment 'ThisDoesNotExist'.\",\"@location.error\":{\"@odata.type\":\"#AstoriaUnitTests.Stubs.Address\",\"City\":\"Troy\",\"State\":\"New York\"}}}"); HandleExceptionCalls.Should().Be(1); } }
public void TestGetValuesFromODataEntity() { var entity = new ODataEntity(new Dictionary <string, object> { { "A", null }, { "B", 1 }, { "C", new ODataEntity(new Dictionary <string, object> { { "X", "abc" } }) }, { "D", ODataValue.FromObject(-1) }, { "F", 1.5 }, }); entity.Get <string>("A").ShouldEqual(null); entity.Get <int>("b").ShouldEqual(1); entity.Get <int?>("b").ShouldEqual(1); entity.Get <ODataValue>("B").Value.ShouldEqual(1); entity.Get <ODataEntity>("c").Get <string>("x").ShouldEqual("abc"); entity.Get <ODataObject>("C").GetType().ShouldEqual(typeof(ODataEntity)); entity.Get <int>("d").ShouldEqual(-1); UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <int>("a")); UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <long>("F")); }
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); } }
/// <summary> /// Writes the property start element. /// </summary> /// <param name="beforePropertyCallback">Action called before anything else is written (if it's not null).</param> /// <param name="propertyName">The name of the property to write.</param> /// <param name="value">The odata value to write.</param> /// <param name="isWritingCollection">true if we are writing a collection instead of an entry.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> private void WritePropertyStart(Action beforePropertyCallback, string propertyName, ODataValue value, bool isWritingCollection, bool isTopLevel) { if (beforePropertyCallback != null) { beforePropertyCallback(); } if (!isTopLevel) { // <d:propertyname> this.XmlWriter.WriteStartElement( isWritingCollection ? string.Empty : AtomConstants.ODataNamespacePrefix, propertyName, AtomConstants.ODataNamespace); } else { // <m:value> this.XmlWriter.WriteStartElement( AtomConstants.ODataMetadataNamespacePrefix, AtomConstants.ODataValueElementName, AtomConstants.ODataMetadataNamespace); // COMPAT 24: Use standard ('d' and 'm') namespace prefixes for top-level property payloads // Top-level collection payloads don't write namespace declarations on the root element (except for the d namespace) // We decided to use the same set of default namespaces on entries, feeds, collections and top-level properties DefaultNamespaceFlags namespaces = DefaultNamespaceFlags.Gml | DefaultNamespaceFlags.GeoRss; if (!this.MessageWriterSettings.AlwaysUseDefaultXmlNamespaceForRootElement) { // DEVNOTE: no need to include the OData namespace here, because we already defined it above. // However, the order will change if we leave it to XmlWriter to add it. So, if the knob hasn't been flipped, // manually add it. namespaces |= DefaultNamespaceFlags.OData; } this.WriteDefaultNamespaceAttributes(namespaces); ODataContextUriBuilder contextUriBuilder = this.AtomOutputContext.CreateContextUriBuilder(); ODataPayloadKind kind = this.AtomOutputContext.MessageWriterSettings.IsIndividualProperty ? ODataPayloadKind.IndividualProperty : ODataPayloadKind.Property; ODataContextUrlInfo contextInfo = ODataContextUrlInfo.Create(value, this.AtomOutputContext.MessageWriterSettings.ODataUri); this.WriteContextUriProperty(contextUriBuilder.BuildContextUri(kind, contextInfo)); } }
/// <summary> /// Adds a new property to the <paramref name="entityType"/>. /// </summary> /// <param name="entityType">The entity type to add the property to.</param> /// <param name="propertyName">The name of the property to add.</param> /// <param name="propertyValue">The value of the property; expected to have a <see cref="EntityModelTypeAnnotation"/> to determine the type of the property.</param> /// <remarks>The method uses the <see cref="EntityModelTypeAnnotation"/> to create a property of the correct type.</remarks> public static EdmEntityType Property(this EdmEntityType entityType, EdmModel model, string propertyName, ODataValue propertyValue) { ExceptionUtilities.CheckArgumentNotNull(entityType, "entityType"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue"); var primitiveValue = propertyValue as ODataPrimitiveValue; if (primitiveValue != null) { entityType.AddStructuralProperty(propertyName, MetadataUtils.GetPrimitiveTypeReference(primitiveValue.Value.GetType())); } var collectionValue = propertyValue as ODataCollectionValue; if (collectionValue != null) { entityType.AddStructuralProperty(propertyName, model.FindDeclaredType(collectionValue.TypeName).ToTypeReference()); } var nullValue = propertyValue as ODataNullValue; if (nullValue != null) { //Since we can't know what type a null value should have been we will just use a string property entityType.AddStructuralProperty(propertyName, MetadataUtils.GetPrimitiveTypeReference(typeof(string))); } var streamValue = propertyValue as ODataStreamReferenceValue; if (streamValue != null) { entityType.AddStructuralProperty(propertyName, EdmPrimitiveTypeKind.Stream); } return(entityType); }
/// <summary> /// Constructor. /// </summary> /// <param name="target">The target of the annotation.</param> /// <param name="term">The term whose value is being expressed through this annotation.</param> /// <param name="value">The annotation's value.</param> private AtomInstanceAnnotation(string target, string term, ODataValue value) { this.target = target; this.term = term; this.value = value; }
internal void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, IDuplicatePropertyNameChecker duplicatePropertyNameChecker, ODataResourceMetadataBuilder metadataBuilder) { this.WritePropertyInfo(property, owningType, isTopLevel, duplicatePropertyNameChecker, metadataBuilder); 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 && !(this.JsonLightOutputContext.MetadataLevel is JsonNoMetadataLevel)) { Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriteStreamValue(streamReferenceValue, property.Name, metadataBuilder); 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; } ODataResourceValue resourceValue = value as ODataResourceValue; if (resourceValue != null) { if (isTopLevel) { throw new ODataException(Strings.ODataMessageWriter_NotAllowedWriteTopLevelPropertyWithResourceValue(property.Name)); } this.WriteResourceProperty(property, resourceValue, isOpenPropertyType); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { if (isTopLevel) { if (collectionValue.Items != null && collectionValue.Items.Any(i => i is ODataResourceValue)) { throw new ODataException(Strings.ODataMessageWriter_NotAllowedWriteTopLevelPropertyWithResourceValue(property.Name)); } } this.WriteCollectionProperty(collectionValue, isOpenPropertyType); return; } ODataBinaryStreamValue streamValue = value as ODataBinaryStreamValue; if (streamValue != null) { this.WriteStreamProperty(streamValue, isOpenPropertyType); return; } }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal abstract string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty);
public void GetInnerValue_Returns_CorrectObject(ODataValue value, object expectedResult) { Assert.Equal(expectedResult, value.GetInnerValue()); }
private Uri CreateIndividualPropertyContextUri(ODataValue value, string resourcePath) { ODataContextUrlInfo info = ODataContextUrlInfo.Create(value, new ODataUri() { Path = new ODataUriParser(edmModel, new Uri(ServiceDocumentUriString), new Uri(ServiceDocumentUriString + resourcePath)).ParsePath() }); Uri contextUrl = this.responseContextUriBuilder.BuildContextUri(ODataPayloadKind.IndividualProperty, info); contextUrl.Should().NotBeNull(); return contextUrl; }
/// <summary> /// Gets the strongly-typed value of the named property. This method can be used in OData queries as long as <paramref name="propertyName"/> /// is a constant or local variable capture /// </summary> /// <typeparam name="TProperty">the property type</typeparam> /// <param name="propertyName">the property name</param> /// <returns>the property value</returns> public TProperty Get <TProperty>(string propertyName) { Throw.IfNull(propertyName, "propertyName"); object result; if (!this.Values.TryGetValue(propertyName, out result)) { throw new ArgumentException("The entity does not contain a value for property '" + propertyName + "'!"); } if (result == null) { if (!typeof(TProperty).CanBeNull()) { throw new InvalidCastException(string.Format( "Property '{0}' has a null value and cannot be cast to requested type '{1}'", propertyName, typeof(TProperty) )); } return(default(TProperty)); // always null due to check above } if (result is TProperty) { return((TProperty)result); } var tProperty = typeof(TProperty); if (tProperty.IsNumeric() && result.GetType().IsNumeric()) { try { return(NumberHelper.CheckedConvert <TProperty>(result)); } catch (Exception ex) { throw new InvalidCastException( string.Format( "Failed to convert property '{0}' value '{1}' of type {2} to requested type {3}", propertyName, result, result.GetType(), tProperty ), ex ); } } if (typeof(ODataObject).IsAssignableFrom(tProperty)) { // at this point, we already know it's not ODataEntity since that would be // handled above. Thus, we can just handle ODataValue return((TProperty)(object)ODataValue.FromObject(result)); } throw new InvalidCastException(string.Format( "value '{0}' of type {1} for property '{2}' is not compatible with requested type {3}", result, result.GetType(), // already checked for null above! propertyName, tProperty )); }
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> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="propertyInfo">The serialization info of current property</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal abstract string GetValueTypeNameForWriting( ODataValue value, PropertySerializationInfo propertyInfo, bool isOpenProperty);