/// <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()); }
private IEdmStructuredObject EnsureModel(IEdmStructuredObject obj) { if (obj != null) { obj.SetModel(this.EdmModel); } return(obj); }
internal IEdmTypeReference GetEdmType(object instance, Type type) { IEdmTypeReference edmType; IEdmObject edmObject = instance as IEdmObject; if (edmObject != null) { IEdmStructuredObject edmStructuredObject = edmObject as IEdmStructuredObject; if (edmStructuredObject != null) { edmStructuredObject.SetModel(Model); } edmType = edmObject.GetEdmType(); if (edmType == null) { throw Error.InvalidOperation(SRResources.EdmTypeCannotBeNull, edmObject.GetType().FullName, typeof(IEdmObject).Name); } } else { if (Model == null) { throw Error.InvalidOperation(SRResources.RequestMustHaveModel); } _typeMappingCache = _typeMappingCache ?? Model.GetTypeMappingCache(); edmType = _typeMappingCache.GetEdmType(type, Model); if (edmType == null) { if (instance != null) { edmType = _typeMappingCache.GetEdmType(instance.GetType(), Model); } if (edmType == null) { throw Error.InvalidOperation(SRResources.ClrTypeNotInModel, type); } } else if (instance != null) { IEdmTypeReference actualType = _typeMappingCache.GetEdmType(instance.GetType(), Model); if (actualType != null && actualType != edmType) { edmType = actualType; } } } return(edmType); }
private EntityInstanceContext(ODataSerializerContext serializerContext, IEdmEntityTypeReference entityType, IEdmStructuredObject edmObject) { if (serializerContext == null) { throw Error.ArgumentNull("serializerContext"); } SerializerContext = serializerContext; EntityType = entityType.EntityDefinition(); EdmObject = edmObject; }
private ResourceContext(ODataSerializerContext serializerContext, IEdmStructuredTypeReference structuredType, IEdmStructuredObject edmObject) { if (serializerContext == null) { throw Error.ArgumentNull("serializerContext"); } SerializerContext = serializerContext; StructuredType = structuredType.StructuredDefinition(); EdmObject = edmObject; }
private ODataSerializer GetSerializer(Type type, object value, ODataSerializerProvider serializerProvider) { ODataSerializer serializer; IEdmObject edmObject = value as IEdmObject; if (edmObject != null) { IEdmStructuredObject edmStructuredObject = edmObject as IEdmStructuredObject; if (edmStructuredObject != null) { edmStructuredObject.SetModel(Request.GetModel()); } IEdmTypeReference edmType = edmObject.GetEdmType(); if (edmType == null) { throw new SerializationException(Error.Format(SRResources.EdmTypeCannotBeNull, edmObject.GetType().FullName, typeof(IEdmObject).Name)); } serializer = serializerProvider.GetEdmTypeSerializer(edmType); if (serializer == null) { string message = Error.Format(SRResources.TypeCannotBeSerialized, edmType.ToTraceString(), typeof(ODataMediaTypeFormatter).Name); throw new SerializationException(message); } } else { var applyClause = Request.ODataProperties().ApplyClause; // get the most appropriate serializer given that we support inheritance. if (applyClause == null) { type = value == null ? type : value.GetType(); } serializer = serializerProvider.GetODataPayloadSerializer(type, Request); if (serializer == null) { string message = Error.Format(SRResources.TypeCannotBeSerialized, type.Name, typeof(ODataMediaTypeFormatter).Name); throw new SerializationException(message); } } return(serializer); }
/// <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); }
private static IEdmStructuredObject AsEdmResourceObject(object resourceInstance, IEdmStructuredTypeReference structuredType, IEdmModel model) { if (structuredType == null) { throw Error.ArgumentNull("structuredType"); } IEdmStructuredObject edmStructuredObject = resourceInstance as IEdmStructuredObject; if (edmStructuredObject != null) { return(edmStructuredObject); } if (structuredType.IsEntity()) { return(new TypedEdmEntityObject(resourceInstance, structuredType.AsEntity(), model)); } Contract.Assert(structuredType.IsComplex()); return(new TypedEdmComplexObject(resourceInstance, structuredType.AsComplex(), model)); }
public static string GetEntityKeyValue(EntityInstanceContext entityContext) { Contract.Assert(entityContext != null); Contract.Assert(entityContext.EntityType != null); Contract.Assert(entityContext.EdmObject != null); IEnumerable <IEdmProperty> keys = entityContext.EntityType.Key(); IEdmStructuredObject entityInstance = entityContext.EdmObject; // TODO: BUG 453795: reflection cleanup if (keys.Count() == 1) { return(GetUriRepresentationForKeyValue(keys.First(), entityContext)); } else { IEnumerable <string> keyValues = keys.Select(key => String.Format( CultureInfo.InvariantCulture, "{0}={1}", key.Name, GetUriRepresentationForKeyValue(key, entityContext))); return(String.Join(",", keyValues)); } }
/// <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); } }
internal static void WriteToStream( Type type, object value, IEdmModel model, ODataVersion version, Uri baseAddress, MediaTypeHeaderValue contentType, IWebApiUrlHelper internaUrlHelper, IWebApiRequestMessage internalRequest, IWebApiHeaders internalRequestHeaders, Func <IServiceProvider, ODataMessageWrapper> getODataMessageWrapper, Func <IEdmTypeReference, ODataSerializer> getEdmTypeSerializer, Func <Type, ODataSerializer> getODataPayloadSerializer, Func <ODataSerializerContext> getODataSerializerContext) { if (model == null) { throw Error.InvalidOperation(SRResources.RequestMustHaveModel); } IEdmStructuredObject edmStructuredObject = value as IEdmStructuredObject; if (edmStructuredObject != null) { edmStructuredObject.SetModel(model); } ODataSerializer serializer = GetSerializer(type, value, internalRequest, getEdmTypeSerializer, getODataPayloadSerializer); ODataPath path = internalRequest.Context.Path; IEdmNavigationSource targetNavigationSource = path == null ? null : path.NavigationSource; // serialize a response IODataResponseMessage responseMessage = PrepareResponseMessage(internalRequest, internalRequestHeaders, getODataMessageWrapper); ODataMessageWriterSettings writerSettings = internalRequest.WriterSettings; writerSettings.BaseUri = baseAddress; writerSettings.Version = version; writerSettings.Validations = writerSettings.Validations & ~ValidationKinds.ThrowOnUndeclaredPropertyForNonOpenType; string metadataLink = internaUrlHelper.CreateODataLink(MetadataSegment.Instance); if (metadataLink == null) { throw new SerializationException(SRResources.UnableToDetermineMetadataUrl); } //Set this variable if the SelectExpandClause is different from the processed clause on the Query options SelectExpandClause selectExpandDifferentFromQueryOptions = null; if (internalRequest.Context.QueryOptions != null && internalRequest.Context.QueryOptions.SelectExpand != null) { if (internalRequest.Context.QueryOptions.SelectExpand.ProcessedSelectExpandClause != internalRequest.Context.ProcessedSelectExpandClause) { selectExpandDifferentFromQueryOptions = internalRequest.Context.ProcessedSelectExpandClause; } } else if (internalRequest.Context.ProcessedSelectExpandClause != null) { selectExpandDifferentFromQueryOptions = internalRequest.Context.ProcessedSelectExpandClause; } writerSettings.ODataUri = new ODataUri { ServiceRoot = baseAddress, // TODO: 1604 Convert webapi.odata's ODataPath to ODL's ODataPath, or use ODL's ODataPath. SelectAndExpand = internalRequest.Context.ProcessedSelectExpandClause, Apply = internalRequest.Context.ApplyClause, Path = (path == null || IsOperationPath(path)) ? null : path.Path, }; ODataMetadataLevel metadataLevel = ODataMetadataLevel.MinimalMetadata; if (contentType != null) { IEnumerable <KeyValuePair <string, string> > parameters = contentType.Parameters.Select(val => new KeyValuePair <string, string>(val.Name, val.Value)); metadataLevel = ODataMediaTypes.GetMetadataLevel(contentType.MediaType, parameters); } using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, writerSettings, model)) { ODataSerializerContext writeContext = getODataSerializerContext(); writeContext.NavigationSource = targetNavigationSource; writeContext.Model = model; writeContext.RootElementName = GetRootElementName(path) ?? "root"; writeContext.SkipExpensiveAvailabilityChecks = serializer.ODataPayloadKind == ODataPayloadKind.ResourceSet; writeContext.Path = path; writeContext.MetadataLevel = metadataLevel; writeContext.QueryOptions = internalRequest.Context.QueryOptions; //Set the SelectExpandClause on the context if it was explicitly specified. if (selectExpandDifferentFromQueryOptions != null) { writeContext.SelectExpandClause = selectExpandDifferentFromQueryOptions; } serializer.WriteObject(value, type, messageWriter, writeContext); } }