/// <summary> /// Tries to convert the given value into an instance of <see cref="ODataValue"/>. /// </summary> /// <param name="property">The property being converted.</param> /// <param name="propertyValue">The property value to convert..</param> /// <param name="serverTypeName">The server type name of the entity whose properties are being populated.</param> /// <param name="visitedComplexTypeObjects">Set of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <param name="odataValue">The odata value if one was created.</param> /// <returns>Whether or not the value was converted.</returns> private bool TryConvertPropertyValue(ClientPropertyAnnotation property, object propertyValue, string serverTypeName, HashSet <object> visitedComplexTypeObjects, out ODataValue odataValue) { if (property.IsKnownType) { odataValue = CreateODataPrimitivePropertyValue(property, propertyValue); return(true); } if (property.IsEnumType) { string enumValue; if (propertyValue == null) { enumValue = null; } else { enumValue = ClientTypeUtil.GetEnumValuesString(propertyValue.ToString(), property.PropertyType); } string typeNameInMetadata = this.requestInfo.ResolveNameFromType(property.PropertyType); odataValue = new ODataEnumValue(enumValue, typeNameInMetadata); return(true); } if (property.IsPrimitiveOrEnumOrComplexCollection) { odataValue = this.CreateODataCollectionPropertyValue(property, propertyValue, serverTypeName, visitedComplexTypeObjects); return(true); } odataValue = null; return(false); }
/// <summary> /// Returns the value of the collection property. /// </summary> /// <param name="property">Collection property details. Must not be null.</param> /// <param name="propertyValue">Collection instance.</param> /// <param name="visitedComplexTypeObjects">List of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <returns>An instance of ODataCollectionValue representing the value of the property.</returns> private ODataCollectionValue CreateODataCollectionPropertyValue(ClientPropertyAnnotation property, object propertyValue, HashSet <object> visitedComplexTypeObjects) { Debug.Assert(property != null, "property != null"); Debug.Assert(property.IsPrimitiveOrComplexCollection, "This method is supposed to be used only for writing collections"); Debug.Assert(property.PropertyName != null, "property.PropertyName != null"); return(this.CreateODataCollection(property.PrimitiveOrComplexCollectionItemType, property.PropertyName, propertyValue, visitedComplexTypeObjects)); }
private static ClientTypeAnnotation GetPropertyType(ClientTypeAnnotation clientType, string propertyName) { ClientPropertyAnnotation property = clientType.GetProperty(propertyName, true); if (property == null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.EpmSourceTree_InaccessiblePropertyOnType(propertyName, clientType.ElementTypeName)); } if (property.IsStreamLinkProperty) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.EpmSourceTree_NamedStreamCannotBeMapped(propertyName, clientType.ElementTypeName)); } if (property.IsSpatialType) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, clientType.ElementTypeName)); } if (property.IsPrimitiveOrComplexCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, clientType.ElementTypeName)); } ClientEdmModel model = ClientEdmModel.GetModel(clientType.MaxProtocolVersion); IEdmType orCreateEdmType = model.GetOrCreateEdmType(property.PropertyType); return(model.GetClientTypeAnnotation(orCreateEdmType)); }
/// <summary> /// Check if this type represents an ATOM-style media link entry and /// if so mark the ClientType as such /// </summary> private void CheckMediaLinkEntry() { this.isMediaLinkEntry = false; // MediaEntryAttribute does not allow multiples, so there can be at most 1 instance on the type. MediaEntryAttribute mediaEntryAttribute = (MediaEntryAttribute)this.ElementType.GetCustomAttributes(typeof(MediaEntryAttribute), true).SingleOrDefault(); if (mediaEntryAttribute != null) { this.isMediaLinkEntry = true; ClientPropertyAnnotation mediaProperty = this.Properties().SingleOrDefault(p => p.PropertyName == mediaEntryAttribute.MediaMemberName); if (mediaProperty == null) { #if OPENSILVER throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.ClientType_MissingMediaEntryProperty( this.ElementTypeName, mediaEntryAttribute.MediaMemberName)); #else throw Microsoft.OData.Client.Error.InvalidOperation(Microsoft.OData.Client.Strings.ClientType_MissingMediaEntryProperty( this.ElementTypeName, mediaEntryAttribute.MediaMemberName)); #endif } this.mediaDataMember = mediaProperty; } // HasStreamAttribute does not allow multiples, so there can be at most 1 instance on the type. bool hasStreamAttribute = this.ElementType.GetCustomAttributes(typeof(HasStreamAttribute), true).Any(); if (hasStreamAttribute) { this.isMediaLinkEntry = true; } }
/// <summary> /// Computes the metadata version of the property. /// </summary> /// <param name="propertyCollection">List of properties for which metadata version needs to be computed.</param> /// <param name="visitedComplexTypes">List of complex type already visited.</param> /// <returns>the metadata version of the property collection.</returns> private Version ComputeVersionForPropertyCollection(IEnumerable<IEdmProperty> propertyCollection, HashSet<IEdmType> visitedComplexTypes) { Version propertyMetadataVersion = Util.ODataVersion4; foreach (IEdmProperty property in propertyCollection) { ClientPropertyAnnotation propertyAnnotation = this.model.GetClientPropertyAnnotation(property); if (property.Type.TypeKind() == EdmTypeKind.Complex && !propertyAnnotation.IsDictionary) { if (visitedComplexTypes == null) { visitedComplexTypes = new HashSet<IEdmType>(EqualityComparer<IEdmType>.Default); } else if (visitedComplexTypes.Contains(property.Type.Definition)) { continue; } visitedComplexTypes.Add(property.Type.Definition); WebUtil.RaiseVersion(ref propertyMetadataVersion, this.ComputeVersionForPropertyCollection(this.model.GetClientTypeAnnotation(property).EdmProperties(), visitedComplexTypes)); } } return propertyMetadataVersion; }
internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataProperty atomProperty, ResponseInfo responseInfo, bool performEntityCheck) { ODataFeed feed = atomProperty.Value as ODataFeed; ODataEntry entry = atomProperty.Value as ODataEntry; if (property.IsKnownType && ((feed != null) || (entry != null))) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkLocalSimple); } Type t = null; if (feed != null) { if (!property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } t = property.EntityCollectionItemType; } if (entry != null) { if (property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } t = property.PropertyType; } if (((t != null) && performEntityCheck) && !ClientTypeUtil.TypeIsEntity(t, responseInfo.MaxProtocolVersion)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidNonEntityType(t.ToString())); } }
internal static Type ValidatePropertyMatch(ClientPropertyAnnotation property, ODataNavigationLink link, ResponseInfo responseInfo, bool performEntityCheck) { Type t = null; if (link.IsCollection.HasValue) { if (link.IsCollection.Value) { if (!property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } t = property.EntityCollectionItemType; } else { if (property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } t = property.PropertyType; } } if (((t != null) && performEntityCheck) && !ClientTypeUtil.TypeIsEntity(t, responseInfo.MaxProtocolVersion)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidNonEntityType(t.ToString())); } return(t); }
private object GetCollectionInstance(ClientPropertyAnnotation property, out bool instanceCreated) { instanceCreated = false; object obj2 = property.GetValue(this.entity); if (obj2 != null) { return(obj2); } instanceCreated = true; Type propertyType = property.PropertyType; if (BindingEntityInfo.IsDataServiceCollection(propertyType, base.RequestInfo.MaxProtocolVersion)) { object[] args = new object[2]; args[1] = TrackingMode.None; return(Activator.CreateInstance(WebUtil.GetDataServiceCollectionOfT(new Type[] { property.EntityCollectionItemType }), args)); } Type c = typeof(List <>).MakeGenericType(new Type[] { property.EntityCollectionItemType }); if (!propertyType.IsAssignableFrom(c)) { c = propertyType; } return(Activator.CreateInstance(c)); }
/// <summary> /// Builds an edm property value from the given annotation. /// </summary> /// <param name="propertyAnnotation">The property annotation.</param> /// <returns>The property value</returns> private IEdmPropertyValue BuildEdmPropertyValue(ClientPropertyAnnotation propertyAnnotation) { var propertyValue = propertyAnnotation.GetValue(this.structuredValue); var edmValue = this.ConvertToEdmValue(propertyValue, propertyAnnotation.EdmProperty.Type); return(new EdmPropertyValue(propertyAnnotation.EdmProperty.Name, edmValue)); }
/// <summary> /// Adds a type annotation to the value if it is primitive and not defined on the server. /// </summary> /// <param name="serverTypeName">The server type name of the entity whose properties are being populated.</param> /// <param name="property">The current property.</param> /// <param name="odataValue">The already converted value of the property.</param> private void AddTypeAnnotationNotDeclaredOnServer(string serverTypeName, ClientPropertyAnnotation property, ODataValue odataValue) { Debug.Assert(property != null, "property != null"); Debug.Assert(property.EdmProperty != null, "property.EdmProperty != null"); #if DEBUG if (odataValue is ODataCollectionValue) { Debug.Assert( !this.requestInfo.TypeResolver.ShouldWriteClientTypeForOpenServerProperty(property.EdmProperty, serverTypeName), "Open collection properties are not yet supported. This method will need to be updated when they are."); } #endif var primitiveValue = odataValue as ODataPrimitiveValue; if (primitiveValue == null) { return; } if (!this.requestInfo.Format.UsingAtom && this.requestInfo.TypeResolver.ShouldWriteClientTypeForOpenServerProperty(property.EdmProperty, serverTypeName) && !JsonSharedUtils.ValueTypeMatchesJsonType(primitiveValue, property.EdmProperty.Type.AsPrimitive())) { // DEVNOTE: it is safe to use the property type name for primitive types because they do not generally support inheritance, // and spatial values always contain their specific type inside the GeoJSON/GML representation. primitiveValue.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = property.EdmProperty.Type.FullName() }); } }
/// <summary> /// Returns a client type of the property on the specified resource type. /// </summary> /// <param name="clientType">The client type to look for the property on.</param> /// <param name="propertyName">The name of the property to look for.</param> /// <returns>The type of the property specified. Note that for collection properties this returns the type of the item of the collection property.</returns> private static ClientTypeAnnotation GetPropertyType(ClientTypeAnnotation clientType, string propertyName) { Debug.Assert(propertyName != null, "propertyName != null"); ClientPropertyAnnotation clientProperty = clientType.GetProperty(propertyName, true); if (clientProperty == null) { throw c.Error.InvalidOperation(c.Strings.EpmSourceTree_InaccessiblePropertyOnType(propertyName, clientType.ElementTypeName)); } if (clientProperty.IsStreamLinkProperty) { throw c.Error.InvalidOperation(c.Strings.EpmSourceTree_NamedStreamCannotBeMapped(propertyName, clientType.ElementTypeName)); } if (clientProperty.IsSpatialType) { throw c.Error.InvalidOperation(c.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, clientType.ElementTypeName)); } if (clientProperty.IsPrimitiveOrComplexCollection) { throw c.Error.InvalidOperation(c.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, clientType.ElementTypeName)); } ClientEdmModel model = clientProperty.Model; IEdmType edmType1 = model.GetOrCreateEdmType(clientProperty.PropertyType); var edmType = edmType1; return(model.GetClientTypeAnnotation(edmType)); }
/// <summary> /// Applies the values of a nested <paramref name="feed"/> to the collection /// <paramref name="property"/> of the specified <paramref name="entry"/>. /// </summary> /// <param name="entry">Entry with collection to be modified.</param> /// <param name="property">Collection property on the entry.</param> /// <param name="feed">Values to apply onto the collection.</param> /// <param name="includeLinks">Whether links that are expanded should be materialized.</param> private void ApplyFeedToCollection( MaterializerEntry entry, ClientPropertyAnnotation property, ODataResourceSet feed, bool includeLinks) { Debug.Assert(entry.Entry != null, "entry != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(feed != null, "feed != null"); ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation collectionType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(property.ResourceSetItemType)); IEnumerable <ODataResource> entries = MaterializerFeed.GetFeed(feed).Entries; foreach (ODataResource feedEntry in entries) { this.Materialize(MaterializerEntry.GetEntry(feedEntry), collectionType.ElementType, includeLinks); } ProjectionPlan continuationPlan = includeLinks ? ODataEntityMaterializer.CreatePlanForDirectMaterialization(property.ResourceSetItemType) : ODataEntityMaterializer.CreatePlanForShallowMaterialization(property.ResourceSetItemType); this.ApplyItemsToCollection( entry, property, entries.Select(e => MaterializerEntry.GetEntry(e).ResolvedObject), feed.NextPageLink, continuationPlan, false); }
internal static object ProjectionInitializeEntity(ODataEntityMaterializer materializer, MaterializerEntry entry, Type expectedType, Type resultType, string[] properties, Func <object, object, Type, object>[] propertyValues) { if (entry.Entry == null) { throw new NullReferenceException(System.Data.Services.Client.Strings.AtomMaterializer_EntryToInitializeIsNull(resultType.FullName)); } if (!entry.EntityHasBeenResolved) { ProjectionEnsureEntryAvailableOfType(materializer, entry, resultType); } else if (!resultType.IsAssignableFrom(entry.ActualType.ElementType)) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_ProjectEntityTypeMismatch(resultType.FullName, entry.ActualType.ElementType.FullName, entry.Entry.Id)); } object resolvedObject = entry.ResolvedObject; for (int i = 0; i < properties.Length; i++) { StreamDescriptor descriptor; string propertyName = properties[i]; ClientPropertyAnnotation annotation = entry.ActualType.GetProperty(propertyName, materializer.ResponseInfo.IgnoreMissingProperties); object target = propertyValues[i](materializer, entry.Entry, expectedType); ODataProperty property = (from p in entry.Entry.Properties where p.Name == propertyName select p).FirstOrDefault <ODataProperty>(); if ((((((property == null) && (entry.NavigationLinks != null)) ? (from l in entry.NavigationLinks where l.Name == propertyName select l).FirstOrDefault <ODataNavigationLink>() : null) != null) || (property != null)) || entry.EntityDescriptor.TryGetNamedStreamInfo(propertyName, out descriptor)) { if (entry.ShouldUpdateFromPayload && (annotation.EdmProperty.Type.TypeKind() == EdmTypeKind.Entity)) { materializer.Log.SetLink(entry, annotation.PropertyName, target); } if (entry.ShouldUpdateFromPayload) { if (!annotation.IsEntityCollection) { if (!annotation.IsPrimitiveOrComplexCollection) { annotation.SetValue(resolvedObject, target, annotation.PropertyName, false); } } else { IEnumerable list = (IEnumerable)target; DataServiceQueryContinuation continuation = materializer.nextLinkTable[list]; Uri nextLink = (continuation == null) ? null : continuation.NextLinkUri; ProjectionPlan plan = (continuation == null) ? null : continuation.Plan; materializer.MergeLists(entry, annotation, list, nextLink, plan); } } else if (annotation.IsEntityCollection) { materializer.FoundNextLinkForUnmodifiedCollection(annotation.GetValue(entry.ResolvedObject) as IEnumerable); } } } return(resolvedObject); }
/// <summary> /// Returns the value of the complex property. /// </summary> /// <param name="property">Property which contains name, type, is key (if false and null value, will throw).</param> /// <param name="propertyValue">property value</param> /// <param name="visitedComplexTypeObjects">List of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <returns>An instance of ODataComplexValue containing the value of the properties of the given complex type.</returns> private ODataComplexValue CreateODataComplexPropertyValue(ClientPropertyAnnotation property, object propertyValue, HashSet <object> visitedComplexTypeObjects) { Debug.Assert(propertyValue != null || !property.IsPrimitiveOrComplexCollection, "Collection items must not be null"); Type propertyType = property.IsPrimitiveOrComplexCollection ? property.PrimitiveOrComplexCollectionItemType : property.PropertyType; return(this.CreateODataComplexValue(propertyType, propertyValue, property.PropertyName, property.IsPrimitiveOrComplexCollection, visitedComplexTypeObjects)); }
/// <summary> /// Gets or creates a collection property on the specified <paramref name="instance"/>. /// </summary> /// <param name="instance">Instance on which to get/create the collection.</param> /// <param name="property">Collection property on the <paramref name="instance"/>.</param> /// <param name="forLoadProperty">Is this collection being created for LoadProperty scenario.</param> /// <returns> /// The collection corresponding to the specified <paramref name="property"/>; /// never null. /// </returns> private object GetOrCreateCollectionProperty(object instance, ClientPropertyAnnotation property, bool forLoadProperty) { Debug.Assert(instance != null, "instance != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(property.IsResourceSet, "property.IsEntityCollection has to be true - otherwise property isn't a collection"); // NOTE: in V1, we would have instantiated nested objects before setting them. object result; result = property.GetValue(instance); if (result == null) { Type collectionType = property.PropertyType; // For backward compatibility we need to have different strategy of collection creation b/w // LoadProperty scenario versus regular collection creation scenario. if (forLoadProperty) { if (BindingEntityInfo.IsDataServiceCollection(collectionType, this.MaterializerContext.Model)) { Debug.Assert(WebUtil.GetDataServiceCollectionOfT(property.EntityCollectionItemType) != null, "DataServiceCollection<> must be available here."); // new DataServiceCollection<property.EntityCollectionItemType>(null, TrackingMode.None) result = Activator.CreateInstance( WebUtil.GetDataServiceCollectionOfT(property.EntityCollectionItemType), null, TrackingMode.None); } else { // Try List<> first because that's what we did in V1/V2, but use the actual property type if it doesn't support List<> Type listCollectionType = typeof(List <>).MakeGenericType(property.EntityCollectionItemType); if (collectionType.IsAssignableFrom(listCollectionType)) { collectionType = listCollectionType; } result = Activator.CreateInstance(collectionType); } } else { if (DSClient.PlatformHelper.IsInterface(collectionType)) { collectionType = typeof(System.Collections.ObjectModel.Collection <>).MakeGenericType(property.EntityCollectionItemType); } result = this.CreateNewInstance(property.EdmProperty.Type, collectionType); } // Update the property value on the instance. property.SetValue(instance, result, property.PropertyName, false /* add */); } Debug.Assert(result != null, "result != null -- otherwise GetOrCreateCollectionProperty didn't fall back to creation"); return(result); }
/// <summary> /// Returns the value of the collection property. /// </summary> /// <param name="property">Collection property details. Must not be null.</param> /// <param name="propertyValue">Collection instance.</param> /// <param name="serverTypeName">The server type name of the entity whose properties are being populated.</param> /// <param name="visitedComplexTypeObjects">List of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <returns>An instance of ODataCollectionValue representing the value of the property.</returns> private ODataCollectionValue CreateODataCollectionPropertyValue(ClientPropertyAnnotation property, object propertyValue, string serverTypeName, HashSet <object> visitedComplexTypeObjects) { Debug.Assert(property != null, "property != null"); Debug.Assert(property.IsPrimitiveOrEnumOrComplexCollection, "This method is supposed to be used only for writing collections"); Debug.Assert(property.PropertyName != null, "property.PropertyName != null"); bool isDynamic = this.requestInfo.TypeResolver.ShouldWriteClientTypeForOpenServerProperty(property.EdmProperty, serverTypeName); return(this.CreateODataCollection(property.PrimitiveOrComplexCollectionItemType, property.PropertyName, propertyValue, visitedComplexTypeObjects, isDynamic)); }
/// <summary> /// Constructs a new instance. /// </summary> /// <param name="requestInfo">Information about the request.</param> /// <param name="mergeOption">Merge option.</param> /// <param name="entityDescriptor">Entity whose property is being loaded.</param> /// <param name="property">Property which is being loaded.</param> internal LoadPropertyResponseInfo( RequestInfo requestInfo, MergeOption mergeOption, EntityDescriptor entityDescriptor, ClientPropertyAnnotation property) : base(requestInfo, mergeOption) { this.EntityDescriptor = entityDescriptor; this.Property = property; }
public void Initialize() { this.clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4); this.clientEdmModel.GetOrCreateEdmType(typeof(TestCustomer)); this.clientEdmModel.GetOrCreateEdmType(typeof(TestOrder)); this.materializerContext = new TestMaterializerContext() { Model = this.clientEdmModel }; this.ordersProperty = this.clientEdmModel.GetClientTypeAnnotation(typeof(TestCustomer)).GetProperty("Orders", UndeclaredPropertyBehavior.ThrowException); }
/// <summary> /// Creates and returns an <see cref="ODataValue"/> for the given primitive value. /// </summary> /// <param name="property">The property being converted.</param> /// <param name="propertyValue">The property value to convert..</param> /// <returns>An ODataValue representing the given value.</returns> private static ODataValue CreateODataPrimitivePropertyValue(ClientPropertyAnnotation property, object propertyValue) { if (propertyValue == null) { return(new ODataNullValue()); } propertyValue = ConvertPrimitiveValueToRecognizedODataType(propertyValue, property.PropertyType); return(new ODataPrimitiveValue(propertyValue)); }
/// <summary> /// Determines whether a given property should be serialized into an insert or update payload. /// </summary> /// <param name="type">The declaring type of the property.</param> /// <param name="property">The property.</param> /// <returns>Whether or not the property should be serialized.</returns> private static bool ShouldSerializeProperty(ClientTypeAnnotation type, ClientPropertyAnnotation property) { // don't write property if it is a dictionary // don't write mime data member or the mime type member for it // link properties need to be ignored // don't write property if it is tagged with IgnoreClientProperty attribute return !property.IsDictionary && property != type.MediaDataMember && !property.IsStreamLinkProperty && (type.MediaDataMember == null || type.MediaDataMember.MimeTypeProperty != property) && !property.PropertyInfo.GetCustomAttributes(typeof(IgnoreClientPropertyAttribute)).Any(); }
/// <summary> /// Returns the resource of the complex property. /// </summary> /// <param name="property">Property which contains name, type, is key (if false and null value, will throw).</param> /// <param name="propertyValue">property value</param> /// <param name="visitedComplexTypeObjects">List of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <returns>An instance of ODataResourceWrapper containing the resource of the properties of the given complex type.</returns> private ODataResourceWrapper CreateODataComplexPropertyResource(ClientPropertyAnnotation property, object propertyValue, HashSet <object> visitedComplexTypeObjects) { Type propertyType = property.IsComplexCollection ? property.PrimitiveOrComplexCollectionItemType : property.PropertyType; if (propertyValue != null && propertyType != propertyValue.GetType()) { Debug.Assert(propertyType.IsAssignableFrom(propertyValue.GetType()), "Type from value should equals to or derived from property type from model."); propertyType = propertyValue.GetType(); } return(this.CreateODataResourceWrapperForComplex(propertyType, propertyValue, property.PropertyName, visitedComplexTypeObjects)); }
private MaterializeAtom ReadPropertyFromRawData(ClientPropertyAnnotation property) { MaterializeAtom atom; DataServiceContext source = (DataServiceContext)base.Source; bool applyingChanges = source.ApplyingChanges; try { source.ApplyingChanges = true; string mime = null; Encoding encoding = null; Type type = property.EntityCollectionItemType ?? property.NullablePropertyType; IList results = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(new Type[] { type })); HttpProcessUtility.ReadContentType(base.ContentType, out mime, out encoding); using (Stream stream = base.GetResponseStream()) { if (property.PropertyType == typeof(byte[])) { int contentLength = (int)base.ContentLength; byte[] buffer = null; if (contentLength >= 0) { buffer = ReadByteArrayWithContentLength(stream, contentLength); } else { buffer = ReadByteArrayChunked(stream); } results.Add(buffer); property.SetValue(this.entity, buffer, this.propertyName, false); } else { StreamReader reader = new StreamReader(stream, encoding); object obj2 = (property.PropertyType == typeof(string)) ? reader.ReadToEnd() : ClientConvert.ChangeType(reader.ReadToEnd(), property.PropertyType); results.Add(obj2); property.SetValue(this.entity, obj2, this.propertyName, false); } } if (property.MimeTypeProperty != null) { property.MimeTypeProperty.SetValue(this.entity, mime, null, false); } atom = MaterializeAtom.CreateWrapper(source, results); } finally { source.ApplyingChanges = applyingChanges; } return(atom); }
private void ApplyFeedToCollection(MaterializerEntry entry, ClientPropertyAnnotation property, ODataFeed feed, bool includeLinks) { ClientEdmModel model = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(property.EntityCollectionItemType)); IEnumerable <ODataEntry> entries = MaterializerFeed.GetFeed(feed).Entries; foreach (ODataEntry entry2 in entries) { this.Materialize(MaterializerEntry.GetEntry(entry2), clientTypeAnnotation.ElementType, includeLinks); } ProjectionPlan continuationPlan = includeLinks ? CreatePlanForDirectMaterialization(property.EntityCollectionItemType) : CreatePlanForShallowMaterialization(property.EntityCollectionItemType); this.ApplyItemsToCollection(entry, property, from e in entries select MaterializerEntry.GetEntry(e).ResolvedObject, feed.NextPageLink, continuationPlan); }
/// <summary> /// Set instance annotation for a property /// </summary> /// <param name="propertyName">Property name</param> /// <param name="instanceAnnotations">Intance annotations to be set</param> /// <param name="type">The type of the containing object</param> /// <param name="declaringInstance">The containing object instance</param> private void SetInstanceAnnotations(string propertyName, IDictionary <string, object> instanceAnnotations, Type type, object declaringInstance) { if (declaringInstance != null) { UndeclaredPropertyBehavior undeclaredPropertyBehavior = this.MaterializerContext.Context.UndeclaredPropertyBehavior; // Get the client property info ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation clientTypeAnnotation = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(type)); ClientPropertyAnnotation clientPropertyAnnotation = clientTypeAnnotation.GetProperty(propertyName, undeclaredPropertyBehavior); Tuple <object, MemberInfo> annotationKeyForProperty = new Tuple <object, MemberInfo>(declaringInstance, clientPropertyAnnotation.PropertyInfo); SetInstanceAnnotations(annotationKeyForProperty, instanceAnnotations); } }
/// <summary> /// Returns the value of the complex property. /// </summary> /// <param name="property">Property which contains name, type, is key (if false and null value, will throw).</param> /// <param name="propertyValue">property value</param> /// <param name="visitedComplexTypeObjects">List of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <returns>An instance of ODataComplexValue containing the value of the properties of the given complex type.</returns> private ODataComplexValue CreateODataComplexPropertyValue(ClientPropertyAnnotation property, object propertyValue, HashSet <object> visitedComplexTypeObjects) { Debug.Assert(propertyValue != null || !property.IsPrimitiveOrEnumOrComplexCollection, "Collection items must not be null"); Type propertyType = property.IsPrimitiveOrEnumOrComplexCollection ? property.PrimitiveOrComplexCollectionItemType : property.PropertyType; if (propertyValue != null && propertyType != propertyValue.GetType()) { Debug.Assert(propertyType.IsAssignableFrom(propertyValue.GetType()), "Type from value should equals to or derived from property type from model."); propertyType = propertyValue.GetType(); } return(this.CreateODataComplexValue(propertyType, propertyValue, property.PropertyName, property.IsPrimitiveOrEnumOrComplexCollection, visitedComplexTypeObjects)); }
private void ApplyItemsToCollection(MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable items, Uri nextLink, ProjectionPlan continuationPlan) { Func <LinkDescriptor, bool> predicate = null; object instance = entry.ShouldUpdateFromPayload ? GetOrCreateCollectionProperty(entry.ResolvedObject, property, null) : null; ClientEdmModel model = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(property.EntityCollectionItemType)); foreach (object obj3 in items) { if (!clientTypeAnnotation.ElementType.IsAssignableFrom(obj3.GetType())) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_EntryIntoCollectionMismatch(obj3.GetType().FullName, clientTypeAnnotation.ElementType.FullName)); } if (entry.ShouldUpdateFromPayload) { property.SetValue(instance, obj3, property.PropertyName, true); this.log.AddedLink(entry, property.PropertyName, obj3); } } if (entry.ShouldUpdateFromPayload) { this.FoundNextLinkForCollection(instance as IEnumerable, nextLink, continuationPlan); } else { this.FoundNextLinkForUnmodifiedCollection(property.GetValue(entry.ResolvedObject) as IEnumerable); } if ((this.mergeOption == MergeOption.OverwriteChanges) || (this.mergeOption == MergeOption.PreserveChanges)) { if (predicate == null) { predicate = delegate(LinkDescriptor x) { if (MergeOption.OverwriteChanges != this.mergeOption) { return(EntityStates.Added != x.State); } return(true); }; } foreach (object obj4 in (from x in base.ResponseInfo.EntityTracker.GetLinks(entry.ResolvedObject, property.PropertyName).Where <LinkDescriptor>(predicate) select x.Target).Except <object>(EnumerateAsElementType <object>(items))) { if (instance != null) { property.RemoveValue(instance, obj4); } this.log.RemovedLink(entry, property.PropertyName, obj4); } } }
internal Uri GetNavigationLink(UriResolver baseUriResolver, ClientPropertyAnnotation property) { LinkInfo linkInfo = null; Uri navigationLink = null; if (this.TryGetLinkInfo(property.PropertyName, out linkInfo)) { navigationLink = linkInfo.NavigationLink; } if (navigationLink == null) { Uri requestUri = Util.CreateUri(property.PropertyName + (property.IsEntityCollection ? "()" : string.Empty), UriKind.Relative); navigationLink = Util.CreateUri(this.GetResourceUri(baseUriResolver, true), requestUri); } return(navigationLink); }
private void MergeLists(MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable list, Uri nextLink, ProjectionPlan plan) { if ((entry.ShouldUpdateFromPayload && (property.NullablePropertyType == list.GetType())) && (property.GetValue(entry.ResolvedObject) == null)) { property.SetValue(entry.ResolvedObject, list, property.PropertyName, false); this.FoundNextLinkForCollection(list, nextLink, plan); foreach (object obj2 in list) { this.log.AddedLink(entry, property.PropertyName, obj2); } } else { this.ApplyItemsToCollection(entry, property, list, nextLink, plan); } }
/// <summary> /// Populates the collection property on the entry's resolved object with the given items enumerator. /// </summary> /// <param name="entry">Entry with collection to be modified.</param> /// <param name="property">Collection property on the entry.</param> /// <param name="items">Values to apply onto the collection.</param> /// <param name="nextLink">Next link for collection continuation.</param> /// <param name="continuationPlan">Projection plan for collection continuation.</param> /// <returns>Collection instance that was populated.</returns> private object PopulateCollectionProperty( MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable <object> items, Uri nextLink, ProjectionPlan continuationPlan) { Debug.Assert(entry.Entry != null || entry.ForLoadProperty, "ODataResource should be non-null except for LoadProperty"); Debug.Assert(property != null, "property != null"); Debug.Assert(items != null, "items != null"); object collection = null; ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation collectionType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(property.ResourceSetItemType)); if (entry.ShouldUpdateFromPayload) { collection = this.GetOrCreateCollectionProperty(entry.ResolvedObject, property, entry.ForLoadProperty); foreach (object item in items) { // Validate that item can be inserted into collection. ValidateCollectionElementTypeIsItemType(item.GetType(), collectionType.ElementType); property.SetValue(collection, item, property.PropertyName, true /* allowAdd? */); this.EntityTrackingAdapter.MaterializationLog.AddedLink(entry, property.PropertyName, item); } this.FoundNextLinkForCollection(collection as IEnumerable, nextLink, continuationPlan); } else { Debug.Assert(!entry.ForLoadProperty, "LoadProperty should always have ShouldUpdateForPayload set to true."); foreach (object item in items) { // Validate that item can be inserted into collection. ValidateCollectionElementTypeIsItemType(item.GetType(), collectionType.ElementType); } this.FoundNextLinkForUnmodifiedCollection(property.GetValue(entry.ResolvedObject) as IEnumerable); } return(collection); }
/// <summary> /// Validates the specified <paramref name="property"/> matches /// the parsed <paramref name="atomProperty"/>. /// </summary> /// <param name="property">Property as understood by the type system.</param> /// <param name="atomProperty">Property as parsed.</param> /// <param name="model">Client model.</param> /// <param name="performEntityCheck">whether to do the entity check or not.</param> internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataProperty atomProperty, ClientEdmModel model, bool performEntityCheck) { Debug.Assert(property != null, "property != null"); Debug.Assert(atomProperty != null, "atomProperty != null"); ODataResourceSet feed = atomProperty.Value as ODataResourceSet; ODataResource entry = atomProperty.Value as ODataResource; if (property.IsKnownType && (feed != null || entry != null)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkLocalSimple); } Type propertyType = null; if (feed != null) { // We need to fail if the payload states that the property is a navigation collection property // and in the client, the property is not a collection property. if (!property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } propertyType = property.EntityCollectionItemType; } if (entry != null) { if (property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } propertyType = property.PropertyType; } // If the server type and the client type does not match, we need to throw. // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa if (propertyType != null && performEntityCheck) { if (!ClientTypeUtil.TypeIsEntity(propertyType, model)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString())); } } }