public void CanConfigureAllLinksViaIdLink() { // Arrange ODataModelBuilder builder = GetCommonModel(); var expectedEditLink = "http://server/service/Products(15)"; var products = builder.EntitySet<EntitySetLinkConfigurationTest_Product>("Products"); products.HasIdLink(c => string.Format( "http://server/service/Products({0})", c.GetPropertyValue("ID") ), followsConventions: false); var actor = builder.EntitySets.Single(); var model = builder.GetEdmModel(); var productType = model.SchemaElements.OfType<IEdmEntityType>().Single(); var productsSet = model.SchemaElements.OfType<IEdmEntityContainer>().Single().EntitySets().Single(); var productInstance = new EntitySetLinkConfigurationTest_Product { ID = 15 }; var serializerContext = new ODataSerializerContext { Model = model, NavigationSource = productsSet }; var entityContext = new EntityInstanceContext(serializerContext, productType.AsReference(), productInstance); var linkBuilderAnnotation = new NavigationSourceLinkBuilderAnnotation(actor); // Act var selfLinks = linkBuilderAnnotation.BuildEntitySelfLinks(entityContext, ODataMetadataLevel.Default); // Assert Assert.NotNull(selfLinks.EditLink); Assert.Equal(expectedEditLink, selfLinks.EditLink.ToString()); Assert.NotNull(selfLinks.ReadLink); Assert.Equal(expectedEditLink, selfLinks.ReadLink.ToString()); Assert.NotNull(selfLinks.IdLink); Assert.Equal(expectedEditLink, selfLinks.IdLink); }
public void WriteObject_WritesValueReturnedFrom_CreateODataCollectionValue() { // 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<ODataCollectionSerializer> serializer = new Mock<ODataCollectionSerializer>(new DefaultODataSerializerProvider()); ODataSerializerContext writeContext = new ODataSerializerContext { RootElementName = "CollectionName", Model = _model }; IEnumerable enumerable = new object[0]; ODataCollectionValue collectionValue = new ODataCollectionValue { TypeName = "NS.Name", Items = new[] { 0, 1, 2 } }; serializer.CallBase = true; serializer .Setup(s => s.CreateODataCollectionValue(enumerable, It.Is<IEdmTypeReference>(e => e.Definition == _edmIntType.Definition), writeContext)) .Returns(collectionValue).Verifiable(); // Act serializer.Object.WriteObject(enumerable, typeof(int[]), messageWriter, writeContext); // Assert serializer.Verify(); stream.Seek(0, SeekOrigin.Begin); string result = new StreamReader(stream).ReadToEnd(); Assert.Equal("{\"@odata.context\":\"http://any/$metadata#Collection(Edm.Int32)\",\"value\":[0,1,2]}", result); }
/// <inheridoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph != null) { ODataEntityReferenceLinks entityReferenceLinks = graph as ODataEntityReferenceLinks; if (entityReferenceLinks == null) { IEnumerable<Uri> uris = graph as IEnumerable<Uri>; if (uris == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } entityReferenceLinks = new ODataEntityReferenceLinks { Links = uris.Select(uri => new ODataEntityReferenceLink { Url = uri }) }; } messageWriter.WriteEntityReferenceLinks(entityReferenceLinks); } }
public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw new ArgumentNullException("messageWriter"); } if (writeContext == null) { throw new ArgumentNullException("writeContext"); } if (graph != null) { Uri[] uris = graph as Uri[]; if (uris == null) { throw new SerializationException("Cannot write the type"); } messageWriter.WriteEntityReferenceLinks(new ODataEntityReferenceLinks { Links = uris.Select(uri => new ODataEntityReferenceLink { Url = uri }) }); } }
public ODataDeltaFeedSerializerTests() { _model = SerializationTestsHelpers.SimpleCustomerOrderModel(); _customerSet = _model.EntityContainer.FindEntitySet("Customers"); _model.SetAnnotationValue(_customerSet.EntityType(), new ClrTypeAnnotation(typeof(Customer))); _path = new ODataPath(new EntitySetPathSegment(_customerSet)); _customers = new[] { new Customer() { FirstName = "Foo", LastName = "Bar", ID = 10, }, new Customer() { FirstName = "Foo", LastName = "Bar", ID = 42, } }; _deltaFeedCustomers = new EdmChangedObjectCollection(_customerSet.EntityType()); EdmDeltaEntityObject newCustomer = new EdmDeltaEntityObject(_customerSet.EntityType()); newCustomer.TrySetPropertyValue("ID", 10); newCustomer.TrySetPropertyValue("FirstName", "Foo"); _deltaFeedCustomers.Add(newCustomer); _customersType = _model.GetEdmTypeReference(typeof(Customer[])).AsCollection(); _writeContext = new ODataSerializerContext() { NavigationSource = _customerSet, Model = _model, Path = _path }; }
public void ODataEntityReferenceLinkSerializer_Serializes_UrisAndEntityReferenceLinks(object uris) { // Arrange ODataEntityReferenceLinksSerializer serializer = new ODataEntityReferenceLinksSerializer(); ODataSerializerContext writeContext = new ODataSerializerContext(); 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 writer = new ODataMessageWriter(message, settings); // Act serializer.WriteObject(uris, typeof(ODataEntityReferenceLinks), writer, writeContext); stream.Seek(0, SeekOrigin.Begin); string result = new StreamReader(stream).ReadToEnd(); // Assert Assert.Equal("{\"@odata.context\":\"http://any/$metadata#Collection($ref)\"," + "\"value\":[{\"@odata.id\":\"http://uri1/\"},{\"@odata.id\":\"http://uri2/\"}]}", result); }
/// <summary> /// Writes the entity result to the response message. /// </summary> /// <param name="graph">The entity result to write.</param> /// <param name="type">The type of the entity.</param> /// <param name="messageWriter">The message writer.</param> /// <param name="writeContext">The writing context.</param> public override void WriteObject( object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { RawResult rawResult = graph as RawResult; if (rawResult != null) { graph = rawResult.Result; type = rawResult.Type; } if (writeContext != null) { graph = RestierPrimitiveSerializer.ConvertToPayloadValue(graph, writeContext); } if (graph == null) { // This is to make ODataRawValueSerializer happily serialize null value. graph = string.Empty; } base.WriteObject(graph, type, messageWriter, writeContext); }
public void Singleton_CanOnlyConfigureIdLinkViaIdLinkFactory() { // Arrange ODataModelBuilder builder = GetSingletonModel(); const string ExpectedEditLink = "http://server/service/Exchange"; var product = builder.Singleton<SingletonProduct>("Exchange"); product.HasIdLink(c => new Uri("http://server/service/Exchange"), followsConventions: false); var exchange = builder.Singletons.Single(); var model = builder.GetEdmModel(); var productType = model.SchemaElements.OfType<IEdmEntityType>().Single(); var singleton = model.SchemaElements.OfType<IEdmEntityContainer>().Single().FindSingleton("Exchange"); var singletonInstance = new SingletonProduct { ID = 15 }; var serializerContext = new ODataSerializerContext { Model = model, NavigationSource = singleton }; var entityContext = new EntityInstanceContext(serializerContext, productType.AsReference(), singletonInstance); var linkBuilderAnnotation = new NavigationSourceLinkBuilderAnnotation(exchange); // Act var selfLinks = linkBuilderAnnotation.BuildEntitySelfLinks(entityContext, ODataMetadataLevel.FullMetadata); // Assert Assert.NotNull(selfLinks.IdLink); Assert.Equal(ExpectedEditLink, selfLinks.IdLink.ToString()); Assert.Null(selfLinks.ReadLink); Assert.Null(selfLinks.EditLink); }
public void CanSerializerSingleton() { // Arrange const string expect = "{" + "\"@odata.context\":\"http://localhost/odata/$metadata#Boss\"," + "\"@odata.id\":\"http://localhost/odata/Boss\"," + "\"@odata.editLink\":\"http://localhost/odata/Boss\"," + "\"EmployeeId\":987,\"EmployeeName\":\"John Mountain\"}"; IEdmModel model = GetEdmModel(); IEdmSingleton singleton = model.EntityContainer.FindSingleton("Boss"); HttpRequestMessage request = GetRequest(model, singleton); ODataSerializerContext readContext = new ODataSerializerContext() { Url = new UrlHelper(request), Path = request.ODataProperties().Path, Model = model, NavigationSource = singleton }; ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider(); EmployeeModel boss = new EmployeeModel {EmployeeId = 987, EmployeeName = "John Mountain"}; MemoryStream bufferedStream = new MemoryStream(); // Act ODataEntityTypeSerializer serializer = new ODataEntityTypeSerializer(serializerProvider); serializer.WriteObject(boss, typeof(EmployeeModel), GetODataMessageWriter(model, bufferedStream), readContext); // Assert string result = Encoding.UTF8.GetString(bufferedStream.ToArray()); Assert.Equal(expect, result); }
/// <inheritdoc/> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (graph == null) { throw Error.ArgumentNull("graph"); } if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } ODataError oDataError = graph as ODataError; if (oDataError == null) { HttpError httpError = graph as HttpError; if (httpError == null) { string message = Error.Format(SRResources.ErrorTypeMustBeODataErrorOrHttpError, graph.GetType().FullName); throw new SerializationException(message); } else { oDataError = httpError.CreateODataError(); } } bool includeDebugInformation = oDataError.InnerError != null; messageWriter.WriteError(oDataError, includeDebugInformation); }
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> /// Creates an <see cref="ODataEnumValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The enum value.</param> /// <param name="enumType">The EDM enum type of the value.</param> /// <param name="writeContext">The serializer write context.</param> /// <returns>The created <see cref="ODataEnumValue"/>.</returns> public virtual ODataEnumValue CreateODataEnumValue(object graph, IEdmEnumTypeReference enumType, ODataSerializerContext writeContext) { if (graph == null) { return null; } string value = null; if (graph.GetType().IsEnum) { value = graph.ToString(); } else { if (graph.GetType() == typeof(EdmEnumObject)) { value = ((EdmEnumObject)graph).Value; } } ODataEnumValue enumValue = new ODataEnumValue(value, enumType.FullName()); ODataMetadataLevel metadataLevel = writeContext != null ? writeContext.MetadataLevel : ODataMetadataLevel.MinimalMetadata; AddTypeNameAnnotationAsNeeded(enumValue, enumType, metadataLevel); return enumValue; }
/// <inheritdoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } IEdmNavigationSource navigationSource = writeContext.NavigationSource; if (navigationSource == null) { throw new SerializationException(SRResources.NavigationSourceMissingDuringSerialization); } var path = writeContext.Path; if (path == null) { throw new SerializationException(SRResources.ODataPathMissing); } ODataWriter writer = messageWriter.CreateODataEntryWriter(navigationSource, path.EdmType as IEdmEntityType); WriteObjectInline(graph, navigationSource.EntityType().ToEdmTypeReference(isNullable: false), writer, writeContext); }
/// <summary> /// Creates an <see cref="ODataPrimitiveValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The primitive value.</param> /// <param name="primitiveType">The EDM primitive type of the value.</param> /// <param name="writeContext">The serializer write context.</param> /// <returns>The created <see cref="ODataPrimitiveValue"/>.</returns> public override ODataPrimitiveValue CreateODataPrimitiveValue( object graph, IEdmPrimitiveTypeReference primitiveType, ODataSerializerContext writeContext) { // The EDM type of the "graph" would override the EDM type of the property when // OData Web API infers the primitiveType. Thus for "graph" of System.DateTime, // the primitiveType is always Edm.DateTimeOffset. // // In EF, System.DateTime is used for SqlDate, SqlDateTime and SqlDateTime2. // All of them have no time zone information thus it is safe to clear the time // zone when converting the "graph" to a DateTimeOffset. if (primitiveType != null && primitiveType.IsDateTimeOffset() && graph is DateTime) { // If DateTime.Kind equals Local, offset should equal the offset of the system's local time zone if (((DateTime)graph).Kind == DateTimeKind.Local) { graph = new DateTimeOffset((DateTime)graph, TimeZoneInfo.Local.GetUtcOffset((DateTime)graph)); } else { graph = new DateTimeOffset((DateTime)graph, TimeSpan.Zero); } } return base.CreateODataPrimitiveValue(graph, primitiveType, writeContext); }
public void Apply_Doesnot_Override_UserConfiguration() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); var vehicles = builder.EntitySet<Vehicle>("vehicles"); var car = builder.AddEntityType(typeof(Car)); var paintAction = vehicles.EntityType.Action("Paint"); paintAction.HasActionLink(ctxt => new Uri("http://localhost/ActionTestWorks"), followsConventions: false); ActionLinkGenerationConvention convention = new ActionLinkGenerationConvention(); convention.Apply(paintAction, builder); IEdmModel model = builder.GetEdmModel(); var vehiclesEdmSet = model.EntityContainer.FindEntitySet("vehicles"); var carEdmType = model.FindDeclaredType("System.Web.OData.Builder.TestModels.Car") as IEdmEntityType; var paintEdmAction = model.GetAvailableProcedures( model.FindDeclaredType("System.Web.OData.Builder.TestModels.Car") as IEdmEntityType).Single() as IEdmAction; Assert.NotNull(paintEdmAction); HttpConfiguration configuration = new HttpConfiguration(); configuration.Routes.MapODataServiceRoute(model); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost"); request.SetConfiguration(configuration); ActionLinkBuilder actionLinkBuilder = model.GetActionLinkBuilder(paintEdmAction); var serializerContext = new ODataSerializerContext { Model = model, NavigationSource = vehiclesEdmSet, Url = request.GetUrlHelper() }; var entityContext = new EntityInstanceContext(serializerContext, carEdmType.AsReference(), new Car { Model = 2009, Name = "Contoso" }); Uri link = actionLinkBuilder.BuildActionLink(entityContext); Assert.Equal("http://localhost/ActionTestWorks", link.AbsoluteUri); }
public void Ctor_ThatBuildsNestedContext_CopiesProperties() { // Arrange CustomersModelWithInheritance model = new CustomersModelWithInheritance(); ODataSerializerContext context = new ODataSerializerContext { NavigationSource = model.Customers, MetadataLevel = ODataMetadataLevel.FullMetadata, Model = model.Model, Path = new ODataPath(), Request = new HttpRequestMessage(), RootElementName = "somename", SelectExpandClause = new SelectExpandClause(new SelectItem[0], allSelected: true), SkipExpensiveAvailabilityChecks = true, Url = new UrlHelper() }; EntityInstanceContext entity = new EntityInstanceContext { SerializerContext = context }; SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true); IEdmNavigationProperty navProp = model.Customer.NavigationProperties().First(); // Act ODataSerializerContext nestedContext = new ODataSerializerContext(entity, selectExpand, navProp); // Assert Assert.Equal(context.MetadataLevel, nestedContext.MetadataLevel); Assert.Same(context.Model, nestedContext.Model); Assert.Same(context.Path, nestedContext.Path); Assert.Same(context.Request, nestedContext.Request); Assert.Equal(context.RootElementName, nestedContext.RootElementName); Assert.Equal(context.SkipExpensiveAvailabilityChecks, nestedContext.SkipExpensiveAvailabilityChecks); Assert.Same(context.Url, nestedContext.Url); }
/// <inheritdoc /> public override void WriteObjectInline(object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) { if (writer == null) { throw Error.ArgumentNull("writer"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (expectedType == null) { throw Error.ArgumentNull("expectedType"); } if (graph == null) { throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, Feed)); } IEnumerable enumerable = graph as IEnumerable; // Data to serialize if (enumerable == null) { throw new SerializationException( Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } WriteFeed(enumerable, expectedType, writer, writeContext); }
public void Convention_GeneratesUri_ForActionBoundToEntity() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Customer>("Customers"); var action = builder.EntityType<Customer>().Action("MyAction"); action.Parameter<string>("param"); IEdmModel model = builder.GetEdmModel(); // Act HttpConfiguration configuration = new HttpConfiguration(); configuration.MapODataServiceRoute("odata", "odata", model); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:123"); request.SetConfiguration(configuration); request.ODataProperties().RouteName = "odata"; IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); var edmType = model.SchemaElements.OfType<IEdmEntityType>().First(e => e.Name == "Customer"); var serializerContext = new ODataSerializerContext { Model = model, NavigationSource = customers, Url = request.GetUrlHelper() }; var entityContext = new EntityInstanceContext(serializerContext, edmType.AsReference(), new Customer { Id = 109 }); // Assert var edmAction = model.SchemaElements.OfType<IEdmAction>().First(f => f.Name == "MyAction"); Assert.NotNull(edmAction); ActionLinkBuilder actionLinkBuilder = model.GetActionLinkBuilder(edmAction); Uri link = actionLinkBuilder.BuildActionLink(entityContext); Assert.Equal("http://localhost:123/odata/Customers(109)/Default.MyAction", link.AbsoluteUri); }
/// <inheritdoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase; if (entitySet == null) { throw new SerializationException(SRResources.EntitySetMissingDuringSerialization); } IEdmTypeReference feedType = writeContext.GetEdmType(graph, type); Contract.Assert(feedType != null); IEdmEntityTypeReference entityType = GetEntityType(feedType); ODataWriter writer = messageWriter.CreateODataFeedWriter(entitySet, entityType.EntityDefinition()); WriteObjectInline(graph, feedType, writer, writeContext); }
/// <inheritdoc/> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph != null) { ODataEntityReferenceLink entityReferenceLink = graph as ODataEntityReferenceLink; if (entityReferenceLink == null) { Uri uri = graph as Uri; if (uri == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } entityReferenceLink = new ODataEntityReferenceLink { Url = uri }; } messageWriter.WriteEntityReferenceLink(entityReferenceLink); } }
/// <summary> /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties, /// navigation properties, and actions to select and expand for the given <paramref name="writeContext"/>. /// </summary> /// <param name="entityType">The entity type of the entry that would be written.</param> /// <param name="writeContext">The serializer context to be used while creating the collection.</param> /// <remarks>The default constructor is for unit testing only.</remarks> public SelectExpandNode(IEdmEntityType entityType, ODataSerializerContext writeContext) : this(writeContext.SelectExpandClause, entityType, writeContext.Model) { var queryOptionParser = new ODataQueryOptionParser( writeContext.Model, entityType, writeContext.NavigationSource, _extraQueryParameters); var selectExpandClause = queryOptionParser.ParseSelectAndExpand(); if (selectExpandClause != null) { foreach (SelectItem selectItem in selectExpandClause.SelectedItems) { ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem; if (expandItem != null) { ValidatePathIsSupported(expandItem.PathToNavigationProperty); NavigationPropertySegment navigationSegment = (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment; IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty; if (!ExpandedNavigationProperties.ContainsKey(navigationProperty)) { ExpandedNavigationProperties.Add(navigationProperty, expandItem.SelectAndExpand); } } } } SelectedNavigationProperties.ExceptWith(ExpandedNavigationProperties.Keys); }
public void WriteObject_WritesValueReturnedFrom_CreateODataCollectionValue() { // Arrange MemoryStream stream = new MemoryStream(); IODataResponseMessage message = new ODataMessageWrapper(stream); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.SetContentType(ODataFormat.Atom); ODataMessageWriter messageWriter = new ODataMessageWriter(message, settings); Mock<ODataCollectionSerializer> serializer = new Mock<ODataCollectionSerializer>(new DefaultODataSerializerProvider()); ODataSerializerContext writeContext = new ODataSerializerContext { RootElementName = "CollectionName", Model = _model }; IEnumerable enumerable = new object[0]; ODataCollectionValue collectionValue = new ODataCollectionValue { TypeName = "NS.Name", Items = new[] { 0, 1, 2 } }; serializer.CallBase = true; serializer .Setup(s => s.CreateODataCollectionValue(enumerable, It.Is<IEdmTypeReference>(e => e.Definition == _edmIntType.Definition), writeContext)) .Returns(collectionValue).Verifiable(); // Act serializer.Object.WriteObject(enumerable, typeof(int[]), messageWriter, writeContext); // Assert serializer.Verify(); stream.Seek(0, SeekOrigin.Begin); XElement element = XElement.Load(stream); Assert.Equal("value", element.Name.LocalName); Assert.Equal(3, element.Descendants().Count()); Assert.Equal(new[] { "0", "1", "2" }, element.Descendants().Select(e => e.Value)); }
public override void WriteObjectInline(object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) { if (graph != null) { base.WriteObjectInline(graph, expectedType, writer, writeContext); } }
/// <summary> /// Creates an <see cref="ODataPrimitiveValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The primitive value.</param> /// <param name="primitiveType">The EDM primitive type of the value.</param> /// <param name="writeContext">The serializer write context.</param> /// <returns>The created <see cref="ODataPrimitiveValue"/>.</returns> public virtual ODataPrimitiveValue CreateODataPrimitiveValue(object graph, IEdmPrimitiveTypeReference primitiveType, ODataSerializerContext writeContext) { ODataMetadataLevel metadataLevel = writeContext != null ? writeContext.MetadataLevel : ODataMetadataLevel.Default; // TODO: Bug 467598: validate the type of the object being passed in here with the underlying primitive type. return CreatePrimitive(graph, primitiveType, metadataLevel); }
public void WriteObject_Throws_RootElementNameMissing() { ODataSerializerContext writeContext = new ODataSerializerContext(); ODataPrimitiveSerializer serializer = new ODataPrimitiveSerializer(); Assert.Throws<ArgumentException>( () => serializer.WriteObject(42, typeof(int), ODataTestUtil.GetMockODataMessageWriter(), writeContext), "The 'RootElementName' property is required on 'ODataSerializerContext'.\r\nParameter name: writeContext"); }
/// <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(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, property.Type, 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); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; }
public void WriteObject_Throws_ODataPathMissing() { ODataEntityReferenceLinksSerializer serializer = new ODataEntityReferenceLinksSerializer(); ODataSerializerContext writeContext = new ODataSerializerContext { EntitySet = _customerSet }; Assert.Throws<SerializationException>( () => serializer.WriteObject(graph: null, type: typeof(ODataEntityReferenceLinks), messageWriter: ODataTestUtil.GetMockODataMessageWriter(), writeContext: writeContext), "The operation cannot be completed because no ODataPath is available for the request."); }
public void GenerateSelfLink_GeneratesExpectedSelfLink(bool includeCast, string expectedIdLink) { HttpRequestMessage request = GetODataRequest(_model.Model); var serializerContext = new ODataSerializerContext { Model = _model.Model, EntitySet = _model.Customers, Url = request.GetUrlHelper() }; var entityContext = new EntityInstanceContext(serializerContext, _model.SpecialCustomer.AsReference(), new { ID = 42 }); string idLink = entityContext.GenerateSelfLink(includeCast); Assert.Equal(expectedIdLink, idLink); }
public void WriteObject_Throws_NavigationPropertyMissingDuringSerialization() { ODataEntityReferenceLinksSerializer serializer = new ODataEntityReferenceLinksSerializer(); ODataSerializerContext writeContext = new ODataSerializerContext { EntitySet = _customerSet, Path = new ODataPath() }; Assert.Throws<SerializationException>( () => serializer.WriteObject(graph: null, type: typeof(ODataEntityReferenceLinks), messageWriter: ODataTestUtil.GetMockODataMessageWriter(), writeContext: writeContext), "The related navigation property could not be found from the OData path. The related navigation property is required to serialize the payload."); }
internal ODataProperty CreateProperty(object graph, IEdmTypeReference expectedType, string elementName, ODataSerializerContext writeContext) { Contract.Assert(elementName != null); return new ODataProperty { Name = elementName, Value = CreateODataValue(graph, expectedType, writeContext) }; }
/// <summary> /// Writes the given object specified by the parameter graph as a part of an existing OData message using the given /// messageWriter and the writeContext. /// </summary> /// <param name="graph">The object to be written.</param> /// <param name="expectedType">The expected EDM type of the object represented by <paramref name="graph"/>.</param> /// <param name="writer">The <see cref="ODataWriter" /> to be used for writing.</param> /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param> public virtual void WriteObjectInline(object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) { throw Error.NotSupported(SRResources.WriteObjectInlineNotSupported, GetType().Name); }
/// <summary> /// Creates an <see cref="ODataPrimitiveValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The primitive value.</param> /// <param name="primitiveType">The EDM primitive type of the value.</param> /// <param name="writeContext">The serializer write context.</param> /// <returns>The created <see cref="ODataPrimitiveValue"/>.</returns> public virtual ODataPrimitiveValue CreateODataPrimitiveValue(object graph, IEdmPrimitiveTypeReference primitiveType, ODataSerializerContext writeContext) { // TODO: Bug 467598: validate the type of the object being passed in here with the underlying primitive type. return(CreatePrimitive(graph, primitiveType, writeContext)); }
/// <summary> /// Create the <see cref="ODataFeed"/> to be written for the given feed instance. /// </summary> /// <param name="feedInstance">The instance representing the feed being written.</param> /// <param name="feedType">The EDM type of the feed being written.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataFeed"/> object.</returns> public virtual ODataFeed CreateODataFeed(IEnumerable feedInstance, IEdmCollectionTypeReference feedType, ODataSerializerContext writeContext) { ODataFeed feed = new ODataFeed(); if (writeContext.EntitySet != null) { IEdmModel model = writeContext.Model; EntitySetLinkBuilderAnnotation linkBuilder = model.GetEntitySetLinkBuilder(writeContext.EntitySet); FeedContext feedContext = new FeedContext { Request = writeContext.Request, RequestContext = writeContext.RequestContext, EntitySet = writeContext.EntitySet, Url = writeContext.Url, FeedInstance = feedInstance }; Uri feedSelfLink = linkBuilder.BuildFeedSelfLink(feedContext); if (feedSelfLink != null) { feed.SetAnnotation(new AtomFeedMetadata() { SelfLink = new AtomLinkMetadata() { Relation = "self", Href = feedSelfLink } }); } } feed.Id = new Uri("http://schemas.datacontract.org/2004/07/" + feedType.FullName()); if (writeContext.ExpandedEntity == null) { // If we have more OData format specific information apply it now, only if we are the root feed. PageResult odataFeedAnnotations = feedInstance as PageResult; if (odataFeedAnnotations != null) { feed.Count = odataFeedAnnotations.Count; feed.NextPageLink = odataFeedAnnotations.NextPageLink; } else if (writeContext.Request != null) { feed.NextPageLink = writeContext.Request.ODataProperties().NextLink; long?countValue = writeContext.Request.ODataProperties().TotalCount; if (countValue.HasValue) { feed.Count = countValue.Value; } } } else { // nested feed ITruncatedCollection truncatedCollection = feedInstance as ITruncatedCollection; if (truncatedCollection != null && truncatedCollection.IsTruncated) { feed.NextPageLink = GetNestedNextPageLink(writeContext, truncatedCollection.PageSize); } } return(feed); }
internal List <ODataProperty> AppendDynamicProperties(object source, IEdmStructuredTypeReference structuredType, ODataSerializerContext writeContext, List <ODataProperty> declaredProperties, string[] selectedDynamicProperties) { Contract.Assert(source != null); Contract.Assert(structuredType != null); Contract.Assert(writeContext != null); Contract.Assert(writeContext.Model != null); bool nullDynamicPropertyEnabled = false; if (source is EdmDeltaComplexObject || source is EdmDeltaEntityObject) { nullDynamicPropertyEnabled = true; } else if (writeContext.Request != null) { HttpConfiguration configuration = writeContext.Request.GetConfiguration(); if (configuration != null) { nullDynamicPropertyEnabled = configuration.HasEnabledNullDynamicProperty(); } } PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary( structuredType.StructuredDefinition(), writeContext.Model); IEdmStructuredObject structuredObject = source as IEdmStructuredObject; object value; IDelta delta = source as IDelta; if (delta == null) { if (dynamicPropertyInfo == null || structuredObject == null || !structuredObject.TryGetPropertyValue(dynamicPropertyInfo.Name, out value) || value == null) { return(null); } } else { value = ((EdmStructuredObject)structuredObject).TryGetDynamicProperties(); } IDictionary <string, object> dynamicPropertyDictionary = (IDictionary <string, object>)value; // Build a HashSet to store the declared property names. // It is used to make sure the dynamic property name is different from all declared property names. HashSet <string> declaredPropertyNameSet = new HashSet <string>(declaredProperties.Select(p => p.Name)); List <ODataProperty> dynamicProperties = new List <ODataProperty>(); IEnumerable <KeyValuePair <string, object> > dynamicPropertiesToSelect = dynamicPropertyDictionary.Where( x => !selectedDynamicProperties.Any() || selectedDynamicProperties.Contains(x.Key)); foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertiesToSelect) { if (String.IsNullOrEmpty(dynamicProperty.Key)) { continue; } if (dynamicProperty.Value == null) { if (nullDynamicPropertyEnabled) { dynamicProperties.Add(new ODataProperty { Name = dynamicProperty.Key, Value = new ODataNullValue() }); } continue; } if (declaredPropertyNameSet.Contains(dynamicProperty.Key)) { throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName, dynamicProperty.Key, structuredType.FullName()); } IEdmTypeReference edmTypeReference = writeContext.GetEdmType(dynamicProperty.Value, dynamicProperty.Value.GetType()); if (edmTypeReference == null) { throw Error.NotSupported(SRResources.TypeOfDynamicPropertyNotSupported, dynamicProperty.Value.GetType().FullName, dynamicProperty.Key); } ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference); if (propertySerializer == null) { throw Error.NotSupported(SRResources.DynamicPropertyCannotBeSerialized, dynamicProperty.Key, edmTypeReference.FullName()); } dynamicProperties.Add(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext)); } return(dynamicProperties); }
/// <summary> /// Create the <see cref="ODataResourceSet"/> to be written for the given resourceSet instance. /// </summary> /// <param name="resourceSetInstance">The instance representing the resourceSet being written.</param> /// <param name="resourceSetType">The EDM type of the resourceSet being written.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataResourceSet"/> object.</returns> public virtual ODataResourceSet CreateResourceSet(IEnumerable resourceSetInstance, IEdmCollectionTypeReference resourceSetType, ODataSerializerContext writeContext) { ODataResourceSet resourceSet = new ODataResourceSet { TypeName = resourceSetType.FullName() }; IEdmStructuredTypeReference structuredType = GetResourceType(resourceSetType).AsStructured(); if (writeContext.NavigationSource != null && structuredType.IsEntity()) { ResourceSetContext resourceSetContext = new ResourceSetContext { Request = writeContext.Request, RequestContext = writeContext.RequestContext, EntitySetBase = writeContext.NavigationSource as IEdmEntitySetBase, Url = writeContext.Url, ResourceSetInstance = resourceSetInstance }; IEdmEntityType entityType = structuredType.AsEntity().EntityDefinition(); var operations = writeContext.Model.GetAvailableOperationsBoundToCollection(entityType); var odataOperations = CreateODataOperations(operations, resourceSetContext, writeContext); foreach (var odataOperation in odataOperations) { ODataAction action = odataOperation as ODataAction; if (action != null) { resourceSet.AddAction(action); } else { resourceSet.AddFunction((ODataFunction)odataOperation); } } } if (writeContext.ExpandedResource == null) { // If we have more OData format specific information apply it now, only if we are the root feed. PageResult odataResourceSetAnnotations = resourceSetInstance as PageResult; if (odataResourceSetAnnotations != null) { resourceSet.Count = odataResourceSetAnnotations.Count; resourceSet.NextPageLink = odataResourceSetAnnotations.NextPageLink; } else if (writeContext.Request != null) { resourceSet.NextPageLink = writeContext.Request.ODataProperties().NextLink; resourceSet.DeltaLink = writeContext.Request.ODataProperties().DeltaLink; long?countValue = writeContext.Request.ODataProperties().TotalCount; if (countValue.HasValue) { resourceSet.Count = countValue.Value; } } } else { // nested resourceSet ITruncatedCollection truncatedCollection = resourceSetInstance as ITruncatedCollection; if (truncatedCollection != null && truncatedCollection.IsTruncated) { resourceSet.NextPageLink = GetNestedNextPageLink(writeContext, truncatedCollection.PageSize); } ICountOptionCollection countOptionCollection = resourceSetInstance as ICountOptionCollection; if (countOptionCollection != null && countOptionCollection.TotalCount != null) { resourceSet.Count = countOptionCollection.TotalCount; } } return(resourceSet); }
/// <summary> /// Writes the given deltaDeletedLink specified by the parameter graph as a part of an existing OData message using the given /// messageWriter and the writeContext. /// </summary> /// <param name="graph">The object to be written.</param> /// <param name="writer">The <see cref="ODataDeltaWriter" /> to be used for writing.</param> /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param> public virtual void WriteDeltaDeletedLink(object graph, ODataDeltaWriter writer, ODataSerializerContext writeContext) { EdmDeltaDeletedLink edmDeltaDeletedLink = graph as EdmDeltaDeletedLink; if (edmDeltaDeletedLink == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } ODataDeltaDeletedLink deltaDeletedLink = new ODataDeltaDeletedLink( edmDeltaDeletedLink.Source, edmDeltaDeletedLink.Target, edmDeltaDeletedLink.Relationship); if (deltaDeletedLink != null) { writer.WriteDeltaDeletedLink(deltaDeletedLink); } }
/// <summary> /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties, /// nested properties, navigation properties, and actions to select and expand for the given <paramref name="writeContext"/>. /// </summary> /// <param name="structuredType">The structural type of the resource that would be written.</param> /// <param name="writeContext">The serializer context to be used while creating the collection.</param> /// <remarks>The default constructor is for unit testing only.</remarks> public SelectExpandNode(IEdmStructuredType structuredType, ODataSerializerContext writeContext) : this(writeContext.SelectExpandClause, structuredType, writeContext.Model) { }
private void WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataDeltaWriter writer, ODataSerializerContext writeContext) { Contract.Assert(writer != null); Contract.Assert(writeContext != null); Contract.Assert(enumerable != null); Contract.Assert(feedType != null); ODataDeltaFeed deltaFeed = CreateODataDeltaFeed(enumerable, feedType.AsCollection(), writeContext); if (deltaFeed == null) { throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, DeltaFeed)); } // save this for later to support JSON odata.streaming. Uri nextPageLink = deltaFeed.NextPageLink; deltaFeed.NextPageLink = null; //Start writing of the Delta Feed writer.WriteStart(deltaFeed); //Iterate over all the entries present and select the appropriate write method. //Write method creates ODataDeltaDeletedEntry / ODataDeltaDeletedLink / ODataDeltaLink or ODataEntry. foreach (object entry in enumerable) { if (entry == null) { throw new SerializationException(SRResources.NullElementInCollection); } IEdmChangedObject edmChangedObject = entry as IEdmChangedObject; if (edmChangedObject == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, enumerable.GetType().FullName)); } switch (edmChangedObject.DeltaKind) { case EdmDeltaEntityKind.DeletedEntry: WriteDeltaDeletedEntry(entry, writer, writeContext); break; case EdmDeltaEntityKind.DeletedLinkEntry: WriteDeltaDeletedLink(entry, writer, writeContext); break; case EdmDeltaEntityKind.LinkEntry: WriteDeltaLink(entry, writer, writeContext); break; case EdmDeltaEntityKind.Entry: { IEdmEntityTypeReference elementType = GetEntityType(feedType); ODataEntityTypeSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType) as ODataEntityTypeSerializer; if (entrySerializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } entrySerializer.WriteDeltaObjectInline(entry, elementType, writer, writeContext); break; } default: break; } } // Subtle and surprising behavior: If the NextPageLink property is set before calling WriteStart(feed), // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if // the next page link is not set when calling WriteStart(feed) but is instead set later on that feed // object before calling WriteEnd(), the next page link will be written at the end, as required for // odata.streaming=true support. if (nextPageLink != null) { deltaFeed.NextPageLink = nextPageLink; } //End Writing of the Delta Feed writer.WriteEnd(); }
/// <summary> /// Writes the given deltaDeletedEntry specified by the parameter graph as a part of an existing OData message using the given /// messageWriter and the writeContext. /// </summary> /// <param name="graph">The object to be written.</param> /// <param name="writer">The <see cref="ODataDeltaWriter" /> to be used for writing.</param> /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param> public virtual void WriteDeltaDeletedEntry(object graph, ODataDeltaWriter writer, ODataSerializerContext writeContext) { EdmDeltaDeletedEntityObject edmDeltaDeletedEntity = graph as EdmDeltaDeletedEntityObject; if (edmDeltaDeletedEntity == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } ODataDeltaDeletedEntry deltaDeletedEntry = new ODataDeltaDeletedEntry( edmDeltaDeletedEntity.Id, edmDeltaDeletedEntity.Reason); if (edmDeltaDeletedEntity.NavigationSource != null) { ODataDeltaSerializationInfo serializationInfo = new ODataDeltaSerializationInfo(); serializationInfo.NavigationSourceName = edmDeltaDeletedEntity.NavigationSource.Name; deltaDeletedEntry.SetSerializationInfo(serializationInfo); } if (deltaDeletedEntry != null) { writer.WriteDeltaDeletedEntry(deltaDeletedEntry); } }
/// <inheritdoc/> /// <remarks>The metadata written is from the model set on the <paramref name="messageWriter"/>. The <paramref name="graph" /> /// is not used.</remarks> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } // NOTE: ODataMessageWriter doesn't have a way to set the IEdmModel. So, there is an underlying assumption here that // the model received by this method and the model passed(from configuration) while building ODataMessageWriter is the same (clr object). messageWriter.WriteMetadataDocument(); }
public void CreateODataComplexValue_WritesAllDeclaredAndDynamicProperties_ForOpenComplexType() { // Arrange IEdmModel model = SerializationTestsHelpers.SimpleOpenTypeModel(); IEdmComplexType addressType = model.FindDeclaredType("Default.Address") as IEdmComplexType; Type simpleOpenAddress = typeof(SimpleOpenAddress); model.SetAnnotationValue <ClrTypeAnnotation>(addressType, new ClrTypeAnnotation(simpleOpenAddress)); IEdmEnumType enumType = model.FindDeclaredType("Default.SimpleEnum") as IEdmEnumType; Type simpleEnumType = typeof(SimpleEnum); model.SetAnnotationValue <ClrTypeAnnotation>(enumType, new ClrTypeAnnotation(simpleEnumType)); model.SetAnnotationValue(addressType, new DynamicPropertyDictionaryAnnotation( simpleOpenAddress.GetProperty("Properties"))); IEdmComplexTypeReference addressTypeRef = addressType.ToEdmTypeReference(isNullable: false).AsComplex(); ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider(); ODataComplexTypeSerializer serializer = new ODataComplexTypeSerializer(serializerProvider); ODataSerializerContext context = new ODataSerializerContext { Model = model }; SimpleOpenAddress address = new SimpleOpenAddress() { Street = "My Way", City = "Redmond", Properties = new Dictionary <string, object>() }; address.Properties.Add("EnumProperty", SimpleEnum.Fourth); address.Properties.Add("GuidProperty", new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA")); address.Properties.Add("DoubleProperty", 99.109); address.Properties.Add("DateTimeProperty", new DateTime(2014, 10, 27)); // Act var odataValue = serializer.CreateODataComplexValue(address, addressTypeRef, context); // Assert ODataComplexValue complexValue = Assert.IsType <ODataComplexValue>(odataValue); Assert.Equal(complexValue.TypeName, "Default.Address"); Assert.Equal(6, complexValue.Properties.Count()); // Verify the declared properties ODataProperty street = Assert.Single(complexValue.Properties.Where(p => p.Name == "Street")); Assert.Equal("My Way", street.Value); ODataProperty city = Assert.Single(complexValue.Properties.Where(p => p.Name == "City")); Assert.Equal("Redmond", city.Value); // Verify the dynamic properties ODataProperty enumProperty = Assert.Single(complexValue.Properties.Where(p => p.Name == "EnumProperty")); ODataEnumValue enumValue = Assert.IsType <ODataEnumValue>(enumProperty.Value); Assert.Equal("Fourth", enumValue.Value); Assert.Equal("Default.SimpleEnum", enumValue.TypeName); ODataProperty guidProperty = Assert.Single(complexValue.Properties.Where(p => p.Name == "GuidProperty")); Assert.Equal(new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA"), guidProperty.Value); ODataProperty doubleProperty = Assert.Single(complexValue.Properties.Where(p => p.Name == "DoubleProperty")); Assert.Equal(99.109, doubleProperty.Value); ODataProperty dateTimeProperty = Assert.Single(complexValue.Properties.Where(p => p.Name == "DateTimeProperty")); Assert.Equal(new DateTimeOffset(new DateTime(2014, 10, 27)), dateTimeProperty.Value); }
private void WriteResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext) { Contract.Assert(writer != null); Contract.Assert(writeContext != null); Contract.Assert(enumerable != null); Contract.Assert(resourceSetType != null); IEdmStructuredTypeReference elementType = GetResourceType(resourceSetType); ODataResourceSet resourceSet = CreateResourceSet(enumerable, resourceSetType.AsCollection(), writeContext); if (resourceSet == null) { throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, ResourceSet)); } IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase; if (entitySet == null) { resourceSet.SetSerializationInfo(new ODataResourceSerializationInfo { IsFromCollection = true, NavigationSourceEntityTypeName = elementType.FullName(), NavigationSourceKind = EdmNavigationSourceKind.UnknownEntitySet, NavigationSourceName = null }); } ODataEdmTypeSerializer resourceSerializer = SerializerProvider.GetEdmTypeSerializer(elementType); if (resourceSerializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } // save this for later to support JSON odata.streaming. Uri nextPageLink = resourceSet.NextPageLink; resourceSet.NextPageLink = null; writer.WriteStart(resourceSet); foreach (object item in enumerable) { if (item == null || item is NullEdmComplexObject) { if (elementType.IsEntity()) { throw new SerializationException(SRResources.NullElementInCollection); } // for null complex element, it can be serialized as "null" in the collection. writer.WriteStart(resource: null); writer.WriteEnd(); } else { resourceSerializer.WriteObjectInline(item, elementType, writer, writeContext); } } // Subtle and surprising behavior: If the NextPageLink property is set before calling WriteStart(resourceSet), // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if // the next page link is not set when calling WriteStart(resourceSet) but is instead set later on that resourceSet // object before calling WriteEnd(), the next page link will be written at the end, as required for // odata.streaming=true support. if (nextPageLink != null) { resourceSet.NextPageLink = nextPageLink; } writer.WriteEnd(); }
/// <inheritdoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase; IEdmTypeReference resourceSetType = writeContext.GetEdmType(graph, type); Contract.Assert(resourceSetType != null); IEdmStructuredTypeReference resourceType = GetResourceType(resourceSetType); ODataWriter writer = messageWriter.CreateODataResourceSetWriter(entitySet, resourceType.StructuredDefinition()); WriteObjectInline(graph, resourceSetType, writer, writeContext); }
/// <inheritdoc/> public sealed override ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext) { if (!expectedType.IsEnum()) { throw Error.InvalidOperation(SRResources.CannotWriteType, typeof(ODataEnumSerializer).Name, expectedType.FullName()); } ODataEnumValue value = CreateODataEnumValue(graph, expectedType.AsEnum(), writeContext); if (value == null) { return(new ODataNullValue()); } return(value); }
/// <summary> /// Creates an <see cref="ODataValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataValue"/> to be created.</param> /// <param name="expectedType">The expected EDM type of the object represented by <paramref name="graph"/>.</param> /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param> /// <returns>The <see cref="ODataValue"/> created.</returns> public virtual ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext) { throw Error.NotSupported(SRResources.CreateODataValueNotSupported, GetType().Name); }
private IEnumerable <ODataOperation> CreateODataOperations(IEnumerable <IEdmOperation> operations, ResourceSetContext resourceSetContext, ODataSerializerContext writeContext) { Contract.Assert(operations != null); Contract.Assert(resourceSetContext != null); Contract.Assert(writeContext != null); foreach (IEdmOperation operation in operations) { ODataOperation oDataOperation = CreateODataOperation(operation, resourceSetContext, writeContext); if (oDataOperation != null) { yield return(oDataOperation); } } }
/// <inheritdoc/> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (writeContext.RootElementName == null) { throw Error.Argument("writeContext", SRResources.RootElementNameMissing, typeof(ODataSerializerContext).Name); } IEdmTypeReference edmType = writeContext.GetEdmType(graph, type); Contract.Assert(edmType != null); messageWriter.WriteProperty(CreateProperty(graph, edmType, writeContext.RootElementName, writeContext)); }
public virtual ODataOperation CreateODataOperation(IEdmOperation operation, ResourceSetContext resourceSetContext, ODataSerializerContext writeContext) { if (operation == null) { throw Error.ArgumentNull("operation"); } if (resourceSetContext == null) { throw Error.ArgumentNull("resourceSetContext"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } ODataMetadataLevel metadataLevel = writeContext.MetadataLevel; IEdmModel model = writeContext.Model; if (metadataLevel != ODataMetadataLevel.FullMetadata) { return(null); } OperationLinkBuilder builder; builder = model.GetOperationLinkBuilder(operation); if (builder == null) { return(null); } Uri target = builder.BuildLink(resourceSetContext); if (target == null) { return(null); } Uri baseUri = new Uri(writeContext.Url.CreateODataLink(MetadataSegment.Instance)); Uri metadata = new Uri(baseUri, "#" + operation.FullName()); ODataOperation odataOperation; IEdmAction action = operation as IEdmAction; if (action != null) { odataOperation = new ODataAction(); } else { odataOperation = new ODataFunction(); } odataOperation.Metadata = metadata; // Always omit the title in minimal/no metadata modes. ODataResourceSerializer.EmitTitle(model, operation, odataOperation); // Omit the target in minimal/no metadata modes unless it doesn't follow conventions. if (metadataLevel == ODataMetadataLevel.FullMetadata || !builder.FollowsConventions) { odataOperation.Target = target; } return(odataOperation); }
/// <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 <IEdmProperty> settableProperties = new List <IEdmProperty>(complexType.ComplexDefinition().Properties()); if (complexObject.IsDeltaResource()) { IDelta deltaProperty = graph as IDelta; Contract.Assert(deltaProperty != null); IEnumerable <string> changedProperties = deltaProperty.GetChangedPropertyNames(); settableProperties = settableProperties.Where(p => changedProperties.Contains(p.Name)).ToList(); } List <ODataProperty> propertyCollection = new List <ODataProperty>(); foreach (IEdmProperty property in settableProperties) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { if (propertyValue != null && propertyType != null && propertyType.IsComplex()) { IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType()); if (actualType != null && propertyType != actualType) { propertyType = actualType; } } var odataProperty = propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext); if (odataProperty != null) { propertyCollection.Add(odataProperty); } } } // 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); }
public void Property_Items_IsInitialized() { ODataSerializerContext context = new ODataSerializerContext(); Assert.NotNull(context.Items); }
/// <summary> /// Creates an <see cref="ODataCollectionValue"/> for the enumerable represented by <paramref name="enumerable"/>. /// </summary> /// <param name="enumerable">The value of the collection to be created.</param> /// <param name="elementType">The element EDM type of the collection.</param> /// <param name="writeContext">The serializer context to be used while creating the collection.</param> /// <returns>The created <see cref="ODataCollectionValue"/>.</returns> public virtual ODataCollectionValue CreateODataCollectionValue(IEnumerable enumerable, IEdmTypeReference elementType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (elementType == null) { throw Error.ArgumentNull("elementType"); } ArrayList valueCollection = new ArrayList(); if (enumerable != null) { ODataEdmTypeSerializer itemSerializer = null; foreach (object item in enumerable) { if (item == null) { if (elementType.IsNullable) { valueCollection.Add(value: null); continue; } throw new SerializationException(SRResources.NullElementInCollection); } IEdmTypeReference actualType = writeContext.GetEdmType(item, item.GetType()); Contract.Assert(actualType != null); itemSerializer = itemSerializer ?? SerializerProvider.GetEdmTypeSerializer(actualType); if (itemSerializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, actualType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } // ODataCollectionWriter expects the individual elements in the collection to be the underlying // values and not ODataValues. valueCollection.Add( itemSerializer.CreateODataValue(item, actualType, writeContext).GetInnerValue()); } } // Ideally, we'd like to do this: // string typeName = _edmCollectionType.FullName(); // But ODataLib currently doesn't support .FullName() for collections. As a workaround, we construct the // collection type name the hard way. string typeName = "Collection(" + elementType.FullName() + ")"; // ODataCollectionValue is only a V3 property, arrays inside Complex Types or Entity types are only supported in V3 // if a V1 or V2 Client requests a type that has a collection within it ODataLib will throw. ODataCollectionValue value = new ODataCollectionValue { Items = valueCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return(value); }
/// <inheridoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } IEdmEntitySet entitySet = writeContext.EntitySet; if (entitySet == null) { throw new SerializationException(SRResources.EntitySetMissingDuringSerialization); } if (writeContext.Path == null) { throw new SerializationException(SRResources.ODataPathMissing); } IEdmNavigationProperty navigationProperty = writeContext.Path.GetNavigationProperty(); if (navigationProperty == null) { throw new SerializationException(SRResources.NavigationPropertyMissingDuringSerialization); } if (graph != null) { ODataEntityReferenceLinks entityReferenceLinks = graph as ODataEntityReferenceLinks; if (entityReferenceLinks == null) { IEnumerable <Uri> uris = graph as IEnumerable <Uri>; if (uris == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } entityReferenceLinks = new ODataEntityReferenceLinks { Links = uris.Select(uri => new ODataEntityReferenceLink { Url = uri }) }; } messageWriter.WriteEntityReferenceLinks(entityReferenceLinks, entitySet, navigationProperty); } }
public void CreateODataComplexValue_WritesDynamicCollectionProperty_ForOpenComplexType() { // Arrange IEdmModel model = SerializationTestsHelpers.SimpleOpenTypeModel(); IEdmComplexType addressType = model.FindDeclaredType("Default.Address") as IEdmComplexType; Type simpleOpenAddress = typeof(SimpleOpenAddress); model.SetAnnotationValue <ClrTypeAnnotation>(addressType, new ClrTypeAnnotation(simpleOpenAddress)); IEdmEnumType enumType = model.FindDeclaredType("Default.SimpleEnum") as IEdmEnumType; Type simpleEnumType = typeof(SimpleEnum); model.SetAnnotationValue <ClrTypeAnnotation>(enumType, new ClrTypeAnnotation(simpleEnumType)); model.SetAnnotationValue(addressType, new DynamicPropertyDictionaryAnnotation( simpleOpenAddress.GetProperty("Properties"))); IEdmComplexTypeReference addressTypeRef = addressType.ToEdmTypeReference(isNullable: false).AsComplex(); ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider(); ODataComplexTypeSerializer serializer = new ODataComplexTypeSerializer(serializerProvider); ODataSerializerContext context = new ODataSerializerContext { Model = model }; SimpleOpenAddress address = new SimpleOpenAddress() { Street = "One Way", City = "One City", Properties = new Dictionary <string, object>() }; address.Properties.Add("CollectionProperty", new[] { 1.1, 2.2 }); // Act var odataValue = serializer.CreateODataComplexValue(address, addressTypeRef, context); // Assert ODataComplexValue complexValue = Assert.IsType <ODataComplexValue>(odataValue); Assert.Equal(complexValue.TypeName, "Default.Address"); Assert.Equal(3, complexValue.Properties.Count()); // Verify the declared properties ODataProperty street = Assert.Single(complexValue.Properties.Where(p => p.Name == "Street")); Assert.Equal("One Way", street.Value); ODataProperty city = Assert.Single(complexValue.Properties.Where(p => p.Name == "City")); Assert.Equal("One City", city.Value); // Verify the dynamic properties ODataProperty enumProperty = Assert.Single(complexValue.Properties.Where(p => p.Name == "CollectionProperty")); ODataCollectionValue collectionValue = Assert.IsType <ODataCollectionValue>(enumProperty.Value); Assert.Equal("Collection(Edm.Double)", collectionValue.TypeName); Assert.Equal(new List <double> { 1.1, 2.2 }, collectionValue.Items.OfType <double>().ToList()); }
/// <inheritdoc/> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph != null) { ODataEntityReferenceLink entityReferenceLink = graph as ODataEntityReferenceLink; if (entityReferenceLink == null) { Uri uri = graph as Uri; if (uri == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName)); } entityReferenceLink = new ODataEntityReferenceLink { Url = uri }; } messageWriter.WriteEntityReferenceLink(entityReferenceLink); } }
public void CreateODataComplexValue_WritesNestedOpenComplexTypes() { // Arrange IEdmModel model = SerializationTestsHelpers.SimpleOpenTypeModel(); IEdmComplexType addressType = model.FindDeclaredType("Default.Address") as IEdmComplexType; Type simpleOpenAddress = typeof(SimpleOpenAddress); model.SetAnnotationValue <ClrTypeAnnotation>(addressType, new ClrTypeAnnotation(simpleOpenAddress)); model.SetAnnotationValue(addressType, new DynamicPropertyDictionaryAnnotation( simpleOpenAddress.GetProperty("Properties"))); IEdmComplexType zipCodeType = model.FindDeclaredType("Default.ZipCode") as IEdmComplexType; Type simpleOpenZipCode = typeof(SimpleOpenZipCode); model.SetAnnotationValue <ClrTypeAnnotation>(zipCodeType, new ClrTypeAnnotation(simpleOpenZipCode)); model.SetAnnotationValue(zipCodeType, new DynamicPropertyDictionaryAnnotation( simpleOpenZipCode.GetProperty("Properties"))); IEdmComplexTypeReference addressTypeRef = addressType.ToEdmTypeReference(isNullable: false).AsComplex(); ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider(); ODataComplexTypeSerializer serializer = new ODataComplexTypeSerializer(serializerProvider); ODataSerializerContext context = new ODataSerializerContext { Model = model }; SimpleOpenAddress topAddress = new SimpleOpenAddress() { Street = "TopStreet", City = "TopCity", Properties = new Dictionary <string, object>() { { "PropertOfAddress", "Value1" } } }; SimpleOpenZipCode zipCode = new SimpleOpenZipCode() { Code = 101, Properties = new Dictionary <string, object>() { { "PropertyOfZipCode", "Value2" } } }; SimpleOpenAddress subAddress = new SimpleOpenAddress() { Street = "SubStreet", City = "SubCity", Properties = new Dictionary <string, object>() { { "PropertOfSubAddress", "Value3" } } }; // TopAddress (SimpleOpenAddress) // |-- Street (declare property, string) // |-- City (declare property, string) // |-- PropertyOfAddress (dynamic property, string) // |-- ZipCodeOfAddress (dynamic property, SimpleOpenZipCode) // |-- Code (declare property, int) // |-- PropertyOfZipCode (dynamic property, string) // |-- SubAddressOfZipCode (dynamic property, SimpleOpenAddress) // |-- Street (declare property, string) // |-- City (declare property, string) // |-- PropertyOfAddress (dynamic property, string) zipCode.Properties.Add("SubAddressOfZipCode", subAddress); topAddress.Properties.Add("ZipCodeOfAddress", zipCode); // Act var odataValue = serializer.CreateODataComplexValue(topAddress, addressTypeRef, context); // Assert ODataComplexValue topAddressComplexValue = Assert.IsType <ODataComplexValue>(odataValue); Assert.Equal(topAddressComplexValue.TypeName, "Default.Address"); Assert.Equal(4, topAddressComplexValue.Properties.Count()); // Verify the dynamic "ZipCodeOfAddress" property, it's nested open complex type ODataProperty dynamicProperty = Assert.Single(topAddressComplexValue.Properties.Where(p => p.Name == "ZipCodeOfAddress")); ODataComplexValue zipCodeComplexValue = Assert.IsType <ODataComplexValue>(dynamicProperty.Value); Assert.Equal(zipCodeComplexValue.TypeName, "Default.ZipCode"); Assert.Equal(3, zipCodeComplexValue.Properties.Count()); // Verify the declared "Code" property of ZipCode ODataProperty code = Assert.Single(zipCodeComplexValue.Properties.Where(p => p.Name == "Code")); Assert.Equal(101, code.Value); // Verify the dynamic "SubAddressOfZipCode" property of ZipCode dynamicProperty = Assert.Single(zipCodeComplexValue.Properties.Where(p => p.Name == "SubAddressOfZipCode")); ODataComplexValue subAddressComplexValue = Assert.IsType <ODataComplexValue>(dynamicProperty.Value); Assert.Equal(subAddressComplexValue.TypeName, "Default.Address"); Assert.Equal(3, subAddressComplexValue.Properties.Count()); }
/// <inheritdoc/> public override ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext) { if (!expectedType.IsPrimitive()) { throw Error.InvalidOperation(SRResources.CannotWriteType, typeof(ODataPrimitiveSerializer), expectedType.FullName()); } ODataPrimitiveValue value = CreateODataPrimitiveValue(graph, expectedType.AsPrimitive(), writeContext); if (value == null) { return(NullValue); } return(value); }
/// <inheritdoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null) { throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, DeltaFeed)); } IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase; if (entitySet == null) { throw new SerializationException(SRResources.EntitySetMissingDuringSerialization); } IEdmTypeReference feedType = writeContext.GetEdmType(graph, type); Contract.Assert(feedType != null); IEdmEntityTypeReference entityType = GetEntityType(feedType); ODataDeltaWriter writer = messageWriter.CreateODataDeltaWriter(entitySet, entityType.EntityDefinition()); WriteDeltaFeedInline(graph, feedType, writer, writeContext); }