public void MultipleTypeCustomInstanceAnnotationsOnErrorShouldRoundtrip() { var originalInt = new KeyValuePair<string, ODataValue>("int.error", new ODataPrimitiveValue(1)); var originalDouble = new KeyValuePair<string, ODataValue>("double.error", new ODataPrimitiveValue(double.NaN)); DateTimeOffset dateTimeOffset = new DateTimeOffset(2012, 10, 10, 12, 12, 59, new TimeSpan()); var originalDateTimeOffset = new KeyValuePair<string, ODataValue>("DateTimeOffset.error", new ODataPrimitiveValue(dateTimeOffset)); Date date = new Date(2014, 12, 12); var originalDate = new KeyValuePair<string, ODataValue>("Date.error", new ODataPrimitiveValue(date)); TimeOfDay time = new TimeOfDay(10, 12, 3, 9); var originaltime = new KeyValuePair<string, ODataValue>("TimeOfDay.error", new ODataPrimitiveValue(time)); TimeSpan timeSpan = new TimeSpan(12345); var originalTimeSpan = new KeyValuePair<string, ODataValue>("TimeSpan.error", new ODataPrimitiveValue(timeSpan)); GeographyPoint geographyPoint = GeographyPoint.Create(32.0, -100.0); var originalGeography = new KeyValuePair<string, ODataValue>("Geography.error", new ODataPrimitiveValue(geographyPoint)); var originalNull = new KeyValuePair<string, ODataValue>("null.error", new ODataNullValue()); var complexValue = new ODataComplexValue { TypeName = "ns.ErrorDetails", Properties = new[] { new ODataProperty { Name = "ErrorDetailName", Value = "inner property value" } } }; var originalComplex = new KeyValuePair<string, ODataValue>("sample.error", complexValue); var error = this.WriteThenReadErrorWithInstanceAnnotation(originalInt, originalDouble, originalDate, originalDateTimeOffset, originaltime, originalTimeSpan, originalGeography, originalNull, originalComplex); var annotation = RunBasicVerificationAndGetAnnotationValue("int.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(1); annotation = RunBasicVerificationAndGetAnnotationValue("double.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(double.NaN); annotation = RunBasicVerificationAndGetAnnotationValue("Date.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(date); annotation = RunBasicVerificationAndGetAnnotationValue("DateTimeOffset.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(dateTimeOffset); annotation = RunBasicVerificationAndGetAnnotationValue("TimeOfDay.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(time); annotation = RunBasicVerificationAndGetAnnotationValue("TimeSpan.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(timeSpan); annotation = RunBasicVerificationAndGetAnnotationValue("Geography.error", error); annotation.Should().BeOfType<ODataPrimitiveValue>(); annotation.As<ODataPrimitiveValue>().Value.Should().Be(geographyPoint); annotation = RunBasicVerificationAndGetAnnotationValue("null.error", error); annotation.Should().BeOfType<ODataNullValue>(); annotation = RunBasicVerificationAndGetAnnotationValue("sample.error", error); annotation.Should().BeOfType<ODataComplexValue>(); annotation.As<ODataComplexValue>().Properties.First().Value.Should().Be("inner property value"); }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return complexResource; }
public ODataJsonLightInheritComplexCollectionWriterTests() { collectionStartWithoutSerializationInfo = new ODataCollectionStart(); collectionStartWithSerializationInfo = new ODataCollectionStart(); collectionStartWithSerializationInfo.SetSerializationInfo(new ODataCollectionStartSerializationInfo { CollectionTypeName = "Collection(ns.Address)" }); address = new ODataComplexValue { Properties = new[] { new ODataProperty { Name = "Street", Value = "1 Microsoft Way" }, new ODataProperty { Name = "Zipcode", Value = 98052 }, new ODataProperty { Name = "State", Value = new ODataEnumValue("WA", "ns.StateEnum") }, new ODataProperty { Name = "City", Value = "Shanghai" } }, TypeName = "TestNamespace.DerivedAddress" }; items = new[] { address }; EdmComplexType addressType = new EdmComplexType("ns", "Address"); addressType.AddProperty(new EdmStructuralProperty(addressType, "Street", EdmCoreModel.Instance.GetString(isNullable: true))); addressType.AddProperty(new EdmStructuralProperty(addressType, "Zipcode", EdmCoreModel.Instance.GetInt32(isNullable: true))); var stateEnumType = new EdmEnumType("ns", "StateEnum", isFlags: true); stateEnumType.AddMember("IL", new EdmIntegerConstant(1)); stateEnumType.AddMember("WA", new EdmIntegerConstant(2)); addressType.AddProperty(new EdmStructuralProperty(addressType, "State", new EdmEnumTypeReference(stateEnumType, true))); EdmComplexType derivedAddressType = new EdmComplexType("ns", "DerivedAddress", addressType, false); derivedAddressType.AddProperty(new EdmStructuralProperty(derivedAddressType, "City", EdmCoreModel.Instance.GetString(isNullable: true))); addressTypeReference = new EdmComplexTypeReference(addressType, isNullable: false); derivedAddressTypeReference = new EdmComplexTypeReference(derivedAddressType, isNullable: false); }
private static void AssertODataComplexValueAreEqual(ODataComplexValue expectedComplexValue, ODataComplexValue actualComplexValue) { Assert.IsNotNull(expectedComplexValue); Assert.IsNotNull(actualComplexValue); Assert.AreEqual(expectedComplexValue.TypeName, actualComplexValue.TypeName); AssertODataPropertiesAreEqual(expectedComplexValue.Properties, actualComplexValue.Properties); }
public void DefaultValuesAndPropertiesGetterAndSetterTest() { ODataComplexValue odataComplexValue = new ODataComplexValue(); this.Assert.IsNull(odataComplexValue.Properties, "Expected null default value for property 'Properties'."); List<ODataProperty> properties = new List<ODataProperty>(); odataComplexValue.Properties = properties; this.Assert.AreSame(odataComplexValue.Properties, properties, "Expected reference equal values for property 'Properties'."); }
public void PropertySettersNullTest() { ODataComplexValue odataComplexValue = new ODataComplexValue() { Properties = new List<ODataProperty>() }; odataComplexValue.Properties = null; this.Assert.IsNull(odataComplexValue.Properties, "Expected null value for property 'Properties'."); }
public void ComplexWithPrimitiveValueShouldMaterialize() { ODataComplexValue pointComplexValue = new ODataComplexValue() {Properties = new ODataProperty[] {new ODataProperty() {Name = "X", Value = 15}, new ODataProperty() {Name = "Y", Value = 18}}}; this.CreatePrimitiveValueMaterializationPolicy().MaterializeComplexTypeProperty(typeof(CollectionValueMaterializationPolicyTests.Point), pointComplexValue); pointComplexValue.HasMaterializedValue().Should().BeTrue(); var point = pointComplexValue.GetMaterializedValue().As<CollectionValueMaterializationPolicyTests.Point>(); point.X.Should().Be(15); point.Y.Should().Be(18); }
public void ComplexTypeRoundtripAtomTest() { var age = new ODataProperty() { Name = "Age", Value = (Int16)18 }; var email = new ODataProperty() { Name = "Email", Value = "*****@*****.**" }; var tel = new ODataProperty() { Name = "Tel", Value = "0123456789" }; var id = new ODataProperty() { Name = "ID", Value = Guid.Empty }; ODataComplexValue complexValue = new ODataComplexValue() { TypeName = "NS.PersonalInfo", Properties = new[] { age, email, tel, id } }; this.VerifyComplexTypeRoundtrip(complexValue, "NS.PersonalInfo"); }
public void ComplexTypeCollectionRoundtripAtomTest() { ODataComplexValue subject0 = new ODataComplexValue() { TypeName = "NS.Subject", Properties = new[] { new ODataProperty() { Name = "Name", Value = "English" }, new ODataProperty() { Name = "Score", Value = (Int16)98 } } }; ODataComplexValue subject1 = new ODataComplexValue() { TypeName = "NS.Subject", Properties = new[] { new ODataProperty() { Name = "Name", Value = "Math" }, new ODataProperty() { Name = "Score", Value = (Int16)90 } } }; ODataCollectionValue complexCollectionValue = new ODataCollectionValue { TypeName = "Collection(NS.Subject)", Items = new[] { subject0, subject1 } }; ODataFeedAndEntrySerializationInfo info = new ODataFeedAndEntrySerializationInfo() { NavigationSourceEntityTypeName = subject0.TypeName, NavigationSourceName = "Subjects", ExpectedTypeName = subject0.TypeName }; this.VerifyTypeCollectionRoundtrip(complexCollectionValue, "Subjects", info); }
private void TestBaseLine(ODataComplexValue val, string resVcf, string resJson) { // Write json, compare with baseline Assert.AreEqual( TestHelper.GetResourceString(resJson), TestHelper.GetToplevelPropertyPayloadString(val), "Json baseline"); // Write vcf, compare with baseline Assert.AreEqual( TestHelper.GetResourceString(resVcf), TestHelper.GetToplevelPropertyPayloadString(val, "text/x-vCard", VCardMediaTypeResolver.Instance), "Vcf baseline"); }
public void PropertyGettersAndSettersTest() { string name1 = "ODataPrimitiveProperty"; object value1 = "Hello world"; ODataProperty primitiveProperty = new ODataProperty() { Name = name1, Value = value1, }; this.Assert.AreEqual(name1, primitiveProperty.Name, "Expected equal name values."); this.Assert.AreSame(value1, primitiveProperty.Value, "Expected reference equal values for property 'Value'."); string name2 = "ODataComplexProperty"; ODataComplexValue value2 = new ODataComplexValue() { Properties = new[] { new ODataProperty() { Name = "One", Value = 1 }, new ODataProperty() { Name = "Two", Value = 2 }, } }; ODataProperty complexProperty = new ODataProperty() { Name = name2, Value = value2, }; this.Assert.AreEqual(name2, complexProperty.Name, "Expected equal name values."); this.Assert.AreSame(value2, complexProperty.Value, "Expected reference equal values for property 'Value'."); string name3 = "ODataCollectionProperty"; ODataCollectionValue value3 = new ODataCollectionValue() { Items = new[] { 1, 2, 3 } }; ODataProperty multiValueProperty = new ODataProperty() { Name = name3, Value = value3, }; this.Assert.AreEqual(name3, multiValueProperty.Name, "Expected equal name values."); this.Assert.AreSame(value3, multiValueProperty.Value, "Expected reference equal values for property 'Value'."); }
internal static IEdmValue CreateStructuredEdmValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType) { if (complexType != null) { object typeAnnotation = ReflectionUtils.CreateInstance( odataTypeAnnotationType, new Type[] { typeof(IEdmComplexTypeReference) }, complexType); complexValue.SetAnnotation(typeAnnotation); } return (IEdmValue)ReflectionUtils.CreateInstance( odataEdmStructuredValueType, new Type[] { typeof(ODataComplexValue) }, complexValue); }
public void ReadInline_Calls_ReadComplexValue() { // Arrange ODataDeserializerProvider deserializerProvider = new DefaultODataDeserializerProvider(); Mock<ODataComplexTypeDeserializer> deserializer = new Mock<ODataComplexTypeDeserializer>(deserializerProvider); ODataComplexValue item = new ODataComplexValue(); ODataDeserializerContext readContext = new ODataDeserializerContext(); deserializer.CallBase = true; deserializer.Setup(d => d.ReadComplexValue(item, _addressEdmType, readContext)).Returns(42).Verifiable(); // Act object result = deserializer.Object.ReadInline(item, _addressEdmType, readContext); // Assert deserializer.Verify(); Assert.Equal(42, result); }
public void WriteEntryAndComplex() { Action<ODataJsonLightOutputContext> test = outputContext => { var entry = new ODataEntry(); var complex = new ODataComplexValue() {Properties = new List<ODataProperty>() {new ODataProperty() {Name = "Name", Value = "ComplexName"}}}; entry.Properties = new List<ODataProperty>() {new ODataProperty() {Name = "ID", Value = 1}, new ODataProperty() {Name = "complexProperty", Value = complex}}; var parameterWriter = new ODataJsonLightParameterWriter(outputContext, operation: null); parameterWriter.WriteStart(); var entryWriter = parameterWriter.CreateEntryWriter("entry"); entryWriter.WriteStart(entry); entryWriter.WriteEnd(); parameterWriter.WriteValue("complex", complex); parameterWriter.WriteEnd(); parameterWriter.Flush(); }; WriteAndValidate(test, "{\"entry\":{\"ID\":1,\"complexProperty\":{\"Name\":\"ComplexName\"}},\"complex\":{\"Name\":\"ComplexName\"}}", writingResponse: false); }
static ODataAvroWriterTests() { var type = new EdmEntityType("NS", "SimpleEntry"); type.AddStructuralProperty("TBoolean", EdmPrimitiveTypeKind.Boolean, true); type.AddStructuralProperty("TInt32", EdmPrimitiveTypeKind.Int32, true); type.AddStructuralProperty("TCollection", new EdmCollectionTypeReference(new EdmCollectionType(EdmCoreModel.Instance.GetInt64(false)))); var cpx = new EdmComplexType("NS", "SimpleComplex"); cpx.AddStructuralProperty("TBinary", EdmPrimitiveTypeKind.Binary, true); cpx.AddStructuralProperty("TString", EdmPrimitiveTypeKind.String, true); type.AddStructuralProperty("TComplex", new EdmComplexTypeReference(cpx, true)); TestEntityType = type; binary0 = new byte[] { 4, 7 }; complexValue0 = new ODataComplexValue() { Properties = new[] { new ODataProperty {Name = "TBinary", Value = binary0 ,}, new ODataProperty {Name = "TString", Value = "iamstr",}, }, TypeName = "NS.SimpleComplex" }; longCollection0 = new[] {7L, 9L}; var collectionValue0 = new ODataCollectionValue { Items = longCollection0 }; entry0 = new ODataEntry { Properties = new[] { new ODataProperty {Name = "TBoolean", Value = true,}, new ODataProperty {Name = "TInt32", Value = 32,}, new ODataProperty {Name = "TComplex", Value = complexValue0,}, new ODataProperty {Name = "TCollection", Value = collectionValue0 }, }, TypeName = "NS.SimpleEntry" }; }
/// <summary>Materializes a complex type property.</summary> /// <param name="propertyType">Type of the complex type to set.</param> /// <param name="complexValue">The OData complex value.</param> internal void MaterializeComplexTypeProperty(Type propertyType, ODataComplexValue complexValue) { //// TODO: we decide whether the type is primitive or complex only based on the payload. If there is a mismatch we throw a random exception. //// We should have a similar check to the one we have for non-projection codepath here. if (complexValue == null || complexValue.HasMaterializedValue()) { return; } ClientTypeAnnotation complexType = null; // TODO: We should call type resolver for complex types for projections if they are not instantiated by the user directly // with "new" operator. At the moment we don't do it at all. Let's be consistent for Collections and call type // resolver as we do in DirectMaterializationPlan (even though this is only for negative cases for Collections as property.IsCollection // must have been false otherwise we would have not end up here). // This bug is about investigating when we actually do call type resolver and fix it so that we call it when needed and don't // call it when we should not (i.e. it should not be called for types created with "new" operator"). if (!string.IsNullOrEmpty(complexValue.TypeName)) { complexType = this.MaterializerContext.ResolveTypeForMaterialization(propertyType, complexValue.TypeName); } else { ClientEdmModel edmModel = this.MaterializerContext.Model; complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(propertyType)); } object complexInstance = this.CreateNewInstance(complexType.EdmType.ToEdmTypeReference(true), complexType.ElementType); this.MaterializeDataValues(complexType, complexValue.Properties, this.MaterializerContext.IgnoreMissingProperties); this.ApplyDataValues(complexType, complexValue.Properties, complexInstance); complexValue.SetMaterializedValue(complexInstance); if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization) { this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(complexValue, complexInstance); } }
/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return null; } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model); List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in complexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataOutputFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { if (propertyType != null && propertyType.IsComplex()) { IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType()); if (actualType != null && propertyType != actualType) { propertyType = actualType; } } propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext)); } } // Try to add the dynamic properties if the complex type is open. if (complexType.ComplexDefinition().IsOpen) { List<ODataProperty> dynamicProperties = AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; }
internal static void AddTypeNameAnnotationAsNeeded(ODataComplexValue value, ODataMetadataLevel metadataLevel) { // ODataLib normally has the caller decide whether or not to serialize properties by leaving properties // null when values should not be serialized. The TypeName property is different and should always be // provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not // to serialize the type name (a null value prevents serialization). Contract.Assert(value != null); // Only add an annotation if we want to override ODataLib's default type name serialization behavior. if (ShouldAddTypeNameAnnotation(metadataLevel)) { string typeName; // Provide the type name to serialize (or null to force it not to serialize). if (ShouldSuppressTypeNameSerialization(metadataLevel)) { typeName = null; } else { typeName = value.TypeName; } value.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation { TypeName = typeName }); } }
private static object ConvertComplexValue(ODataComplexValue complexValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmComplexTypeReference edmComplexType; if (propertyType == null) { // open complex property Contract.Assert(!String.IsNullOrEmpty(complexValue.TypeName), "ODataLib should have verified that open complex value has a type name since we provided metadata."); IEdmModel model = readContext.Model; IEdmType edmType = model.FindType(complexValue.TypeName); Contract.Assert(edmType.TypeKind == EdmTypeKind.Complex, "ODataLib should have verified that complex value has a complex resource type."); edmComplexType = new EdmComplexTypeReference(edmType as IEdmComplexType, isNullable: true); propertyType = edmComplexType; } else { edmComplexType = propertyType.AsComplex(); } ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(edmComplexType); return deserializer.ReadInline(complexValue, propertyType, readContext); }
public void ReadComplexValue_Throws_IfDuplicateDynamicPropertyNameFound() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType<SimpleOpenAddress>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenAddress)).AsComplex(); var deserializerProvider = new Mock<ODataDeserializerProvider>().Object; var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { // declared properties new ODataProperty { Name = "Street", Value = "My Way #599" }, new ODataProperty { Name = "City", Value = "Redmond & Shanghai" }, // dynamic properties new ODataProperty { Name = "GuidProperty", Value = new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA") }, new ODataProperty { Name = "GuidProperty", Value = new DateTimeOffset(new DateTime(1992, 1, 1)) } }, TypeName = typeof(SimpleOpenAddress).FullName }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; // Act & Assert Assert.Throws<InvalidOperationException>(() => deserializer.ReadComplexValue(complexValue, addressTypeReference, readContext), "Duplicate dynamic property name 'GuidProperty' found in open type 'System.Web.OData.SimpleOpenAddress'. " + "Each dynamic property name must be unique."); }
public void ReadComplexValue_CanReadDynamicCollectionPropertiesForOpenComplexType() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType<SimpleOpenAddress>(); builder.EnumType<SimpleEnum>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenAddress)).AsComplex(); var deserializerProvider = new DefaultODataDeserializerProvider(); var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataEnumValue enumValue = new ODataEnumValue("Third", typeof(SimpleEnum).FullName); ODataCollectionValue collectionValue = new ODataCollectionValue { TypeName = "Collection(" + typeof(SimpleEnum).FullName + ")", Items = new[] { enumValue, enumValue } }; ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { // declared properties new ODataProperty { Name = "Street", Value = "My Way #599" }, // dynamic properties new ODataProperty { Name = "CollectionProperty", Value = collectionValue } }, TypeName = typeof(SimpleOpenAddress).FullName }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; // Act SimpleOpenAddress address = deserializer.ReadComplexValue(complexValue, addressTypeReference, readContext) as SimpleOpenAddress; // Assert Assert.NotNull(address); // Verify the declared properties Assert.Equal("My Way #599", address.Street); Assert.Null(address.City); // Verify the dynamic properties Assert.NotNull(address.Properties); Assert.Equal(1, address.Properties.Count()); var collectionValues = Assert.IsType<List<SimpleEnum>>(address.Properties["CollectionProperty"]); Assert.NotNull(collectionValues); Assert.Equal(2, collectionValues.Count()); Assert.Equal(SimpleEnum.Third, collectionValues[0]); Assert.Equal(SimpleEnum.Third, collectionValues[1]); }
public void ReadComplexValue_CanReadNestedOpenComplexType() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType<SimpleOpenAddress>(); builder.ComplexType<SimpleOpenZipCode>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenAddress)).AsComplex(); var deserializerProvider = new DefaultODataDeserializerProvider(); var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue zipCodeComplexValue = new ODataComplexValue { Properties = new[] { // declared property new ODataProperty { Name = "Code", Value = 101 }, // dynamic property new ODataProperty { Name = "DateTimeProperty", Value = new DateTimeOffset(new DateTime(2014, 4, 22)) } }, TypeName = typeof(SimpleOpenZipCode).FullName }; ODataComplexValue addressComplexValue = new ODataComplexValue { Properties = new[] { // declared properties new ODataProperty { Name = "Street", Value = "TopStreet" }, new ODataProperty { Name = "City", Value = "TopCity" }, // dynamic properties new ODataProperty { Name = "DoubleProperty", Value = 1.179 }, new ODataProperty { Name = "ZipCodeProperty", Value = zipCodeComplexValue } }, TypeName = typeof(SimpleOpenAddress).FullName }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; // Act SimpleOpenAddress address = deserializer.ReadComplexValue(addressComplexValue, addressTypeReference, readContext) as SimpleOpenAddress; // Assert Assert.NotNull(address); // Verify the declared properties Assert.Equal("TopStreet", address.Street); Assert.Equal("TopCity", address.City); // Verify the dynamic properties Assert.NotNull(address.Properties); Assert.Equal(2, address.Properties.Count()); Assert.Equal(1.179, address.Properties["DoubleProperty"]); // nested open complex type SimpleOpenZipCode zipCode = Assert.IsType<SimpleOpenZipCode>(address.Properties["ZipCodeProperty"]); Assert.Equal(101, zipCode.Code); Assert.Equal(1, zipCode.Properties.Count()); Assert.Equal(new DateTimeOffset(new DateTime(2014, 4, 22)), zipCode.Properties["DateTimeProperty"]); }
public void WriteObject_Calls_CreateODataComplexValue() { // Arrange MemoryStream stream = new MemoryStream(); IODataResponseMessage message = new ODataMessageWrapper(stream); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.SetServiceDocumentUri(new Uri("http://any/")); settings.SetContentType(ODataFormat.Atom); ODataMessageWriter messageWriter = new ODataMessageWriter(message, settings); Mock<ODataComplexTypeSerializer> serializer = new Mock<ODataComplexTypeSerializer>(new DefaultODataSerializerProvider()); ODataSerializerContext writeContext = new ODataSerializerContext { RootElementName = "ComplexPropertyName", Model = _model }; object graph = new object(); ODataComplexValue complexValue = new ODataComplexValue { TypeName = "NS.Name", Properties = new[] { new ODataProperty { Name = "Property1", Value = 42 } } }; serializer.CallBase = true; serializer.Setup(s => s.CreateODataComplexValue(graph, It.Is<IEdmComplexTypeReference>(e => e.Definition == _addressType), writeContext)) .Returns(complexValue).Verifiable(); // Act serializer.Object.WriteObject(graph, typeof(Address), messageWriter, writeContext); // Assert serializer.Verify(); stream.Seek(0, SeekOrigin.Begin); XElement element = XElement.Load(stream); Assert.Equal("value", element.Name.LocalName); Assert.Equal("#NS.Name", element.Attributes().Single(a => a.Name.LocalName == "type").Value); Assert.Equal(1, element.Descendants().Count()); Assert.Equal("42", element.Descendants().Single().Value); Assert.Equal("Property1", element.Descendants().Single().Name.LocalName); }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (!String.IsNullOrEmpty(complexValue.TypeName) && complexType.FullName() != complexValue.TypeName) { // received a derived complex type in a base type deserializer. IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } IEdmComplexType actualType = model.FindType(complexValue.TypeName) as IEdmComplexType; if (actualType == null) { throw new ODataException(Error.Format(SRResources.ComplexTypeNotInModel, complexValue.TypeName)); } if (actualType.IsAbstract) { string message = Error.Format(SRResources.CannotInstantiateAbstractComplexType, complexValue.TypeName); throw new ODataException(message); } IEdmTypeReference actualComplexType = new EdmComplexTypeReference(actualType, isNullable: false); ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(actualComplexType); if (deserializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeDeserialized, actualComplexType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } object resource = deserializer.ReadInline(complexValue, actualComplexType, readContext); EdmStructuredObject structuredObject = resource as EdmStructuredObject; if (structuredObject != null) { structuredObject.ExpectedEdmType = complexType.ComplexDefinition(); } return resource; } else { object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return complexResource; } }
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 AddTypeNameAnnotationAsNeeded_AddsNullAnnotation_InJsonLightNoMetadataMode() { // Arrange string expectedTypeName = "TypeName"; ODataComplexValue value = new ODataComplexValue { TypeName = expectedTypeName }; // Act ODataComplexTypeSerializer.AddTypeNameAnnotationAsNeeded(value, ODataMetadataLevel.NoMetadata); // Assert SerializationTypeNameAnnotation annotation = value.GetAnnotation<SerializationTypeNameAnnotation>(); Assert.NotNull(annotation); // Guard Assert.Null(annotation.TypeName); }
/// <summary> /// Writes an instance annotation. /// </summary> /// <param name="instanceAnnotation">The instance annotation to write.</param> /// <param name="ignoreFilter">Whether to ignore the filter in settings.</param> /// <param name="propertyName">The name of the property this instance annotation applies to</param> internal void WriteInstanceAnnotation(ODataInstanceAnnotation instanceAnnotation, bool ignoreFilter = false, string propertyName = null) { string name = instanceAnnotation.Name; ODataValue value = instanceAnnotation.Value; Debug.Assert(!string.IsNullOrEmpty(name), "name should not be null or empty"); Debug.Assert(!ODataAnnotationNames.IsODataAnnotationName(name), "A reserved name cannot be used as instance annotation key"); Debug.Assert(value != null, "value should not be null because we use ODataNullValue for null instead"); Debug.Assert(!(value is ODataStreamReferenceValue), "!(value is ODataStreamReferenceValue) -- ODataInstanceAnnotation and InstanceAnnotationCollection will throw if the value is a stream value."); Debug.Assert(this.valueSerializer.Model != null, "this.valueSerializer.Model != null"); if (!ignoreFilter && this.valueSerializer.Settings.ShouldSkipAnnotation(name)) { return; } IEdmTypeReference expectedType = MetadataUtils.LookupTypeOfValueTerm(name, this.valueSerializer.Model); if (value is ODataNullValue) { if (expectedType != null && !expectedType.IsNullable) { throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueSerializer_NullValueNotAllowedForInstanceAnnotation(instanceAnnotation.Name, expectedType.FullName())); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteNullValue(); return; } // If we didn't find an expected type from looking up the term in the model, treat this value the same way we would for open property values. // That is, write the type name (unless its a primitive value with a JSON-native type). If we did find an expected type, treat the annotation value like a // declared property with an expected type. This will still write out the type if the value type is more derived than the declared type, for example. bool treatLikeOpenProperty = expectedType == null; ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteComplexValue(complexValue, expectedType, false /*isTopLevel*/, treatLikeOpenProperty, this.valueSerializer.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.valueSerializer.Model, expectedType, value, treatLikeOpenProperty); ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { string collectionTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(collectionValue, expectedType, typeFromValue, treatLikeOpenProperty); if (collectionTypeNameToWrite != null) { this.odataAnnotationWriter.WriteODataTypePropertyAnnotation(name, collectionTypeNameToWrite); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteCollectionValue(collectionValue, expectedType, false /*isTopLevelProperty*/, false /*isInUri*/, treatLikeOpenProperty); return; } ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; Debug.Assert(primitiveValue != null, "Did we add a new subclass of ODataValue?"); string primitiveTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(primitiveValue, expectedType, typeFromValue, treatLikeOpenProperty); if (primitiveTypeNameToWrite != null) { this.odataAnnotationWriter.WriteODataTypePropertyAnnotation(name, primitiveTypeNameToWrite); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WritePrimitiveValue(primitiveValue.Value, expectedType); }
public void AddTypeNameAnnotationAsNeeded_DoesNotAddAnnotation_InDefaultMetadataMode() { // Arrange ODataComplexValue value = new ODataComplexValue(); // Act ODataComplexTypeSerializer.AddTypeNameAnnotationAsNeeded(value, ODataMetadataLevel.MinimalMetadata); // Assert Assert.Null(value.GetAnnotation<SerializationTypeNameAnnotation>()); }
public void ReadComplexValue_CanReadDerivedComplexValue() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType<Address>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressEdmType = model.GetEdmTypeReference(typeof(Address)).AsComplex(); DefaultODataDeserializerProvider deserializerProvider = new DefaultODataDeserializerProvider(); ODataComplexTypeDeserializer deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { new ODataProperty { Name = "Street", Value = "12"}, new ODataProperty { Name = "City", Value = "Redmond"}, new ODataProperty { Name = "UsProp", Value = "UsPropertyValue"} }, TypeName = typeof(UsAddress).FullName }; ODataDeserializerContext readContext = new ODataDeserializerContext { Model = model }; // Act object address = deserializer.ReadComplexValue(complexValue, addressEdmType, readContext); // Assert Assert.NotNull(address); UsAddress usAddress = Assert.IsType<UsAddress>(address); Assert.Equal(usAddress.Street, "12"); Assert.Equal(usAddress.City, "Redmond"); Assert.Null(usAddress.Country); Assert.Null(usAddress.State); Assert.Null(usAddress.ZipCode); Assert.Equal("UsPropertyValue", usAddress.UsProp); }
public void WriteObject_Calls_CreateODataComplexValue() { // Arrange MemoryStream stream = new MemoryStream(); IODataResponseMessage message = new ODataMessageWrapper(stream); ODataMessageWriterSettings settings = new ODataMessageWriterSettings { ODataUri = new ODataUri { ServiceRoot = new Uri("http://any/"), } }; settings.SetContentType(ODataFormat.Json); ODataMessageWriter messageWriter = new ODataMessageWriter(message, settings); Mock<ODataComplexTypeSerializer> serializer = new Mock<ODataComplexTypeSerializer>(new DefaultODataSerializerProvider()); ODataSerializerContext writeContext = new ODataSerializerContext { RootElementName = "ComplexPropertyName", Model = _model }; object graph = new object(); ODataComplexValue complexValue = new ODataComplexValue { TypeName = "NS.Name", Properties = new[] { new ODataProperty { Name = "Property1", Value = 42 } } }; serializer.CallBase = true; serializer.Setup(s => s.CreateODataComplexValue(graph, It.Is<IEdmComplexTypeReference>(e => e.Definition == _addressType), writeContext)) .Returns(complexValue).Verifiable(); // Act serializer.Object.WriteObject(graph, typeof(Address), messageWriter, writeContext); // Assert serializer.Verify(); stream.Seek(0, SeekOrigin.Begin); string result = new StreamReader(stream).ReadToEnd(); Assert.Equal("{\"@odata.context\":\"http://any/$metadata#NS.Name\",\"Property1\":42}", result); }
public void ReadComplexValue_CanReadDynamicPropertiesForOpenComplexType() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType<SimpleOpenAddress>(); builder.EnumType<SimpleEnum>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenAddress)).AsComplex(); var deserializerProvider = new Mock<ODataDeserializerProvider>().Object; var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataEnumValue enumValue = new ODataEnumValue("Third", typeof(SimpleEnum).FullName); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { // declared properties new ODataProperty { Name = "Street", Value = "My Way #599" }, new ODataProperty { Name = "City", Value = "Redmond & Shanghai" }, // dynamic properties new ODataProperty { Name = "GuidProperty", Value = new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA") }, new ODataProperty { Name = "EnumValue", Value = enumValue }, new ODataProperty { Name = "DateTimeProperty", Value = new DateTimeOffset(new DateTime(1992, 1, 1)) } }, TypeName = typeof(SimpleOpenAddress).FullName }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; // Act SimpleOpenAddress address = deserializer.ReadComplexValue(complexValue, addressTypeReference, readContext) as SimpleOpenAddress; // Assert Assert.NotNull(address); // Verify the declared properties Assert.Equal("My Way #599", address.Street); Assert.Equal("Redmond & Shanghai", address.City); // Verify the dynamic properties Assert.NotNull(address.Properties); Assert.Equal(3, address.Properties.Count()); Assert.Equal(new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA"), address.Properties["GuidProperty"]); Assert.Equal(SimpleEnum.Third, address.Properties["EnumValue"]); Assert.Equal(new DateTimeOffset(new DateTime(1992, 1, 1)), address.Properties["DateTimeProperty"]); }