/// <summary> /// Generates a string to be used as the skip token value within the next link. /// </summary> /// <param name="lastMember"> Object based on which SkipToken value will be generated.</param> /// <param name="model">The edm model.</param> /// <param name="orderByNodes">List of orderByNodes used to generate the skiptoken value.</param> /// <returns>Value for the skiptoken to be used in the next link.</returns> private static string GenerateSkipTokenValue(Object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes) { if (lastMember == null) { return(String.Empty); } IEnumerable <IEdmProperty> propertiesForSkipToken = GetPropertiesForSkipToken(lastMember, model, orderByNodes); StringBuilder skipTokenBuilder = new StringBuilder(String.Empty); if (propertiesForSkipToken == null) { return(skipTokenBuilder.ToString()); } int count = 0; string uriLiteral; object value; int lastIndex = propertiesForSkipToken.Count() - 1; IEdmStructuredObject obj = lastMember as IEdmStructuredObject; foreach (IEdmProperty edmProperty in propertiesForSkipToken) { bool islast = count == lastIndex; string clrPropertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, model); if (obj != null) { obj.TryGetPropertyValue(clrPropertyName, out value); } else { value = lastMember.GetType().GetProperty(clrPropertyName).GetValue(lastMember); } if (value == null) { uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401); } else if (edmProperty.Type.IsEnum()) { ODataEnumValue enumValue = new ODataEnumValue(value.ToString(), value.GetType().FullName); uriLiteral = ODataUriUtils.ConvertToUriLiteral(enumValue, ODataVersion.V401, model); } else if (edmProperty.Type.IsDateTimeOffset() && value is DateTime) { var dateTime = (DateTime)value; var dateTimeOffsetValue = TimeZoneInfoHelper.ConvertToDateTimeOffset(dateTime); uriLiteral = ODataUriUtils.ConvertToUriLiteral(dateTimeOffsetValue, ODataVersion.V401, model); } else { uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401, model); } skipTokenBuilder.Append(edmProperty.Name).Append(propertyDelimiter).Append(uriLiteral).Append(islast ? String.Empty : CommaDelimiter.ToString()); count++; } return(skipTokenBuilder.ToString()); }
/// <summary> /// Convert EdmStructuredObject to an object with type. /// </summary> /// <param name="edmStructuredObject">An object with EdmStructuredType.</param> /// <param name="type">Desired object type.</param> /// <returns>Result object.</returns> private static object ConvertEdmStructuredObjectToTypedObject( IEdmStructuredObject edmStructuredObject, Type type) { if (edmStructuredObject == null) { return(null); } var obj = Activator.CreateInstance(type); var propertyInfos = type.GetProperties(); foreach (var propertyInfo in propertyInfos) { if (!propertyInfo.CanWrite) { continue; } object value = null; edmStructuredObject.TryGetPropertyValue(propertyInfo.Name, out value); if (value == null) { propertyInfo.SetValue(obj, value); continue; } if (!propertyInfo.PropertyType.IsInstanceOfType(value)) { var edmObj = value as IEdmStructuredObject; if (edmObj == null) { throw new NotSupportedException(string.Format( CultureInfo.InvariantCulture, propertyInfo.PropertyType.ToString())); } value = ConvertEdmStructuredObjectToTypedObject(edmObj, propertyInfo.PropertyType); } propertyInfo.SetValue(obj, value); } return(obj); }
/// <summary> /// Gets the property value and wraps it in a DTO wrapper if necessary. /// </summary> public static bool TryGetPropertyValue <T>(this IEdmStructuredObject targetObject, string propertyName, out T value) { object internalValue; if (targetObject.TryGetPropertyValue(propertyName, out internalValue)) { // wrap by dto wrapper, if applicable object wrappedValue; if (PropertyValueWrappingHelper.TryWrapEdmObject(internalValue, out wrappedValue)) { internalValue = wrappedValue; } // now cast to desired type if (internalValue is T) { value = (T)internalValue; return(true); } } value = default(T); return(false); }
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); 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(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext)); } return(dynamicProperties); }
/// <summary> /// Appends the dynamic properties of primitive, enum or the collection of them into the given <see cref="ODataResource"/>. /// If the dynamic property is a property of the complex or collection of complex, it will be saved into /// the dynamic complex properties dictionary of <paramref name="resourceContext"/> and be written later. /// </summary> /// <param name="resource">The <see cref="ODataResource"/> describing the resource.</param> /// <param name="selectExpandNode">The <see cref="SelectExpandNode"/> describing the response graph.</param> /// <param name="resourceContext">The context for the resource instance being written.</param> public override void AppendDynamicProperties(ODataResource resource, SelectExpandNode selectExpandNode, ResourceContext resourceContext) { if (!resourceContext.StructuredType.IsOpen || // non-open type (!selectExpandNode.SelectAllDynamicProperties && selectExpandNode.SelectedDynamicProperties == null)) { return; } bool nullDynamicPropertyEnabled = true; // false if (resourceContext.EdmObject is EdmDeltaComplexObject || resourceContext.EdmObject is EdmDeltaEntityObject) { nullDynamicPropertyEnabled = true; } IEdmStructuredType structuredType = resourceContext.StructuredType; IEdmStructuredObject structuredObject = resourceContext.EdmObject; object value; IDelta delta = structuredObject as IDelta; if (delta == null) { PropertyInfo dynamicPropertyInfo = 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>(); // To test SelectedDynamicProperties == null is enough to filter the dynamic properties. // Because if SelectAllDynamicProperties == true, SelectedDynamicProperties should be null always. // So `selectExpandNode.SelectedDynamicProperties == null` covers `SelectAllDynamicProperties == true` scenario. // If `selectExpandNode.SelectedDynamicProperties != null`, then we should test whether the property is selected or not using "Contains(...)". IEnumerable <KeyValuePair <string, object> > dynamicPropertiesToSelect = dynamicPropertyDictionary.Where(x => selectExpandNode.SelectedDynamicProperties == null || selectExpandNode.SelectedDynamicProperties.Contains(x.Key)); foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertiesToSelect) { if (string.IsNullOrWhiteSpace(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)) //{ //continue; //} IEdmTypeReference edmTypeReference = GetEdmType(dynamicProperty.Value, dynamicProperty.Value.GetType()); //for non navigational properties it will be null if (edmTypeReference == null) { dynamicProperties.Add(new ODataProperty { Name = dynamicProperty.Key, Value = new ODataUntypedValue { RawValue = JsonConvert.SerializeObject(dynamicProperty.Value, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.None }), TypeAnnotation = new ODataTypeAnnotation(typeof(string).Name) }, }); } else if (edmTypeReference != null) { 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(edmTypeReference); if (propertySerializer == null) { throw new InvalidOperationException($"Required serilizer for type {edmTypeReference.FullName()} not found"); } dynamicProperties.Add(CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, resourceContext.SerializerContext)); } } } if (dynamicProperties.Any()) { resource.Properties = resource.Properties.Concat(dynamicProperties); } }
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); } }