/// <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 ODataResource 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(writeContext.Context, propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataEdmTypeSerializer).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext)); } } string typeName = complexType.FullName(); var value = new ODataResource { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return(value); }
/// <summary> /// Creates the <see cref="ODataProperty"/> to be written for the given entity and the structural property. /// </summary> /// <param name="structuralProperty">The EDM structural property being written.</param> /// <param name="resourceContext">The context for the entity instance being written.</param> /// <returns>The <see cref="ODataProperty"/> to write.</returns> public virtual ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, ResourceContext resourceContext) { if (structuralProperty == null) { throw Error.ArgumentNull("structuralProperty"); } if (resourceContext == null) { throw Error.ArgumentNull("resourceContext"); } ODataSerializerContext writeContext = resourceContext.SerializerContext; ODataEdmTypeSerializer serializer = SerializerProvider.GetEdmTypeSerializer(resourceContext.Context, structuralProperty.Type); if (serializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, structuralProperty.Type.FullName(), typeof(ODataOutputFormatter).Name)); } object propertyValue = resourceContext.GetPropertyValue(structuralProperty.Name); IEdmTypeReference propertyType = structuralProperty.Type; if (propertyValue != null) { if (!propertyType.IsPrimitive() && !propertyType.IsEnum()) { IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType()); if (propertyType != null && propertyType != actualType) { propertyType = actualType; } } } return(serializer.CreateProperty(propertyValue, propertyType, structuralProperty.Name, writeContext)); }
/// <summary> /// Creates the <see cref="ODataProperty"/> to be written for the given entity and the structural property. /// </summary> /// <param name="structuralProperty">The EDM structural property being written.</param> /// <param name="entityInstanceContext">The context for the entity instance being written.</param> /// <returns>The <see cref="ODataProperty"/> to write.</returns> public virtual async Task <ODataProperty> CreateStructuralPropertyAsync(IEdmStructuralProperty structuralProperty, EntityInstanceContext entityInstanceContext) { if (structuralProperty == null) { throw Error.ArgumentNull("structuralProperty"); } if (entityInstanceContext == null) { throw Error.ArgumentNull("entityInstanceContext"); } ODataSerializerContext writeContext = entityInstanceContext.SerializerContext; ODataEdmTypeSerializer serializer = SerializerProvider.GetEdmTypeSerializer(structuralProperty.Type); if (serializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, structuralProperty.Type.FullName(), typeof(ODataOutputFormatter).Name)); } object propertyValue = entityInstanceContext.GetPropertyValue(structuralProperty.Name); IEdmTypeReference propertyType = structuralProperty.Type; if (propertyValue != null) { IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType()); if (propertyType != null && propertyType != actualType) { propertyType = actualType; } } return(await serializer.CreateProperty(propertyValue, propertyType, structuralProperty.Name, writeContext, entityInstanceContext)); }
internal async Task <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); 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) || dynamicProperty.Value == null) { continue; // skip the null object } 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(await propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext, source, structuredType, null, null)); } return(dynamicProperties); }
/// <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 async Task <ODataComplexValue> CreateODataComplexValueAsync(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( await 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 = await 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 virtual void AppendDynamicProperties(ODataResource resource, SelectExpandNode selectExpandNode, ResourceContext resourceContext) { Contract.Assert(resource != null); Contract.Assert(selectExpandNode != null); Contract.Assert(resourceContext != null); if (!resourceContext.StructuredType.IsOpen || // non-open type (!selectExpandNode.SelectAllDynamicProperties && !selectExpandNode.SelectedDynamicProperties.Any())) { return; } bool nullDynamicPropertyEnabled = false; if (resourceContext.Request != null) { // TODO: /* * HttpConfiguration configuration = resourceContext.Request.GetConfiguration(); * if (configuration != null) * { * nullDynamicPropertyEnabled = configuration.HasEnabledNullDynamicProperty(); * }*/ } IEdmStructuredType structuredType = resourceContext.StructuredType; IEdmStructuredObject structuredObject = resourceContext.EdmObject; object value; IDelta delta = structuredObject as IDelta; if (delta == null) { PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(structuredType, resourceContext.EdmModel); if (dynamicPropertyInfo == null || structuredObject == null || !structuredObject.TryGetPropertyValue(dynamicPropertyInfo.Name, out value) || value == null) { return; } } 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>(resource.Properties.Select(p => p.Name)); List <ODataProperty> dynamicProperties = new List <ODataProperty>(); IEnumerable <KeyValuePair <string, object> > dynamicPropertiesToSelect = dynamicPropertyDictionary.Where( x => !selectExpandNode.SelectedDynamicProperties.Any() || selectExpandNode.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.FullTypeName()); } IEdmTypeReference edmTypeReference = resourceContext.SerializerContext.GetEdmType(dynamicProperty.Value, dynamicProperty.Value.GetType()); if (edmTypeReference == null) { throw Error.NotSupported(SRResources.TypeOfDynamicPropertyNotSupported, dynamicProperty.Value.GetType().FullName, dynamicProperty.Key); } if (edmTypeReference.IsStructured() || (edmTypeReference.IsCollection() && edmTypeReference.AsCollection().ElementType().IsStructured())) { if (resourceContext.DynamicComplexProperties == null) { resourceContext.DynamicComplexProperties = new ConcurrentDictionary <string, object>(); } resourceContext.DynamicComplexProperties.Add(dynamicProperty); } else { ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(resourceContext.Context, edmTypeReference); if (propertySerializer == null) { throw Error.NotSupported(SRResources.DynamicPropertyCannotBeSerialized, dynamicProperty.Key, edmTypeReference.FullName()); } dynamicProperties.Add(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, resourceContext.SerializerContext)); } } if (dynamicProperties.Any()) { resource.Properties = resource.Properties.Concat(dynamicProperties); } }