protected static void MaterializeDataValues(ClientTypeAnnotation actualType, IEnumerable <ODataProperty> values, bool ignoreMissingProperties) { foreach (ODataProperty property in values) { if (!(property.Value is ODataStreamReferenceValue)) { string name = property.Name; ClientPropertyAnnotation annotation = actualType.GetProperty(name, ignoreMissingProperties); if (annotation != null) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(annotation.PropertyType)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidEntityType(annotation.EntityCollectionItemType ?? annotation.PropertyType)); } if (annotation.IsKnownType) { MaterializePrimitiveDataValue(annotation.NullablePropertyType, property); } } } } }
/// <summary>Materializes the specified <paramref name="entry"/>.</summary> /// <param name="entry">Entry with object to materialize.</param> /// <param name="expectedEntryType">Expected type for the entry.</param> /// <param name="includeLinks">Whether links that are expanded should be materialized.</param> /// <remarks>This is a payload-driven materialization process.</remarks> internal void Materialize(MaterializerEntry entry, Type expectedEntryType, bool includeLinks) { Debug.Assert(entry.Entry != null, "entry != null"); Debug.Assert( entry.ResolvedObject == null || entry.ResolvedObject == this.EntityTrackingAdapter.TargetInstance, "entry.ResolvedObject == null || entry.ResolvedObject == this.targetInstance -- otherwise getting called twice"); Debug.Assert(expectedEntryType != null, "expectedType != null"); // ResolvedObject will already be assigned when we have a TargetInstance, for example. if (!this.EntityTrackingAdapter.TryResolveExistingEntity(entry, expectedEntryType)) { // If the type is a derived one this call will resolve to derived type, cannot put code in ResolveByCreatingWithType as this is used by projection and in this case // the type cannot be changed or updated ClientTypeAnnotation actualType = this.MaterializerContext.ResolveTypeForMaterialization(expectedEntryType, entry.Entry.TypeName); this.ResolveByCreatingWithType(entry, actualType.ElementType); } Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise ResolveOrCreateInstnace didn't do its job"); this.MaterializeResolvedEntry(entry, includeLinks); }
protected static void MaterializeComplexTypeProperty(Type propertyType, ODataComplexValue complexValue, bool ignoreMissingProperties, System.Data.Services.Client.ResponseInfo responseInfo) { object instance = null; if ((complexValue != null) && !complexValue.HasMaterializedValue()) { ClientTypeAnnotation actualType = null; if (WebUtil.IsWireTypeCollection(complexValue.TypeName)) { actualType = responseInfo.TypeResolver.ResolveEdmTypeName(propertyType, complexValue.TypeName); } else { ClientEdmModel model = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion); actualType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(propertyType)); } instance = Util.ActivatorCreateInstance(propertyType, new object[0]); MaterializeDataValues(actualType, complexValue.Properties, ignoreMissingProperties); ApplyDataValues(actualType, complexValue.Properties, ignoreMissingProperties, responseInfo, instance); complexValue.SetMaterializedValue(instance); } }
/// <summary> /// Materializes the link properties if any with the url in the response payload /// </summary> /// <param name="actualType">Actual client type that is getting materialized.</param> /// <param name="entry">MaterializerEntry instance containing all the links that came in the response.</param> private static void ApplyLinkProperties( ClientTypeAnnotation actualType, MaterializerEntry entry) { Debug.Assert(actualType != null, "actualType != null"); Debug.Assert(entry.Entry != null, "entry != null"); if (entry.ShouldUpdateFromPayload) { foreach (var linkProperty in actualType.Properties().Where(p => p.PropertyType == typeof(DataServiceStreamLink))) { string propertyName = linkProperty.PropertyName; StreamDescriptor streamDescriptor; if (entry.EntityDescriptor.TryGetNamedStreamInfo(propertyName, out streamDescriptor)) { // At this time we have materialized the stream link onto the stream descriptor object // we'll always make sure the stream link is the same instance on the entity and the descriptor linkProperty.SetValue(entry.ResolvedObject, streamDescriptor.StreamLink, propertyName, true /*allowAdd*/); } } } }
/// <summary>Materializes a complex type property.</summary> /// <param name="propertyType">Type of the complex type to set.</param> /// <param name="complexValue">The OData complex value.</param> internal void MaterializeComplexTypeProperty(Type propertyType, ODataComplexValue complexValue) { //// TODO: we decide whether the type is primitive or complex only based on the payload. If there is a mismatch we throw a random exception. //// We should have a similar check to the one we have for non-projection codepath here. if (complexValue == null || complexValue.HasMaterializedValue()) { return; } ClientTypeAnnotation complexType = null; // TODO: We should call type resolver for complex types for projections if they are not instantiated by the user directly // with "new" operator. At the moment we don't do it at all. Let's be consistent for Collections and call type // resolver as we do in DirectMaterializationPlan (even though this is only for negative cases for Collections as property.IsCollection // must have been false otherwise we would have not end up here). // This bug is about investigating when we actually do call type resolver and fix it so that we call it when needed and don't // call it when we should not (i.e. it should not be called for types created with "new" operator"). if (!string.IsNullOrEmpty(complexValue.TypeName)) { complexType = this.MaterializerContext.ResolveTypeForMaterialization(propertyType, complexValue.TypeName); } else { ClientEdmModel edmModel = this.MaterializerContext.Model; complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(propertyType)); } object complexInstance = this.CreateNewInstance(complexType.EdmType.ToEdmTypeReference(true), complexType.ElementType); this.MaterializeDataValues(complexType, complexValue.Properties, this.MaterializerContext.IgnoreMissingProperties); this.ApplyDataValues(complexType, complexValue.Properties, complexInstance); complexValue.SetMaterializedValue(complexInstance); if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization) { this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(complexValue, complexInstance); } }
/// <summary>Materializes a primitive value. No op or non-primitive values.</summary> /// <param name="type">Type of value to set.</param> /// <param name="wireTypeName">Type name from the payload.</param> /// <param name="value">Value of primitive provided by ODL.</param> /// <param name="throwOnNullMessage">The exception message if the value is null.</param> /// <param name="materializedValue">The materialized value.</param> private void MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, Func <string> throwOnNullMessage, out object materializedValue) { Debug.Assert(type != null, "type != null"); ClientTypeAnnotation nestedElementType = null; Type underlyingType = Nullable.GetUnderlyingType(type) ?? type; PrimitiveType ptype; bool knownType = PrimitiveType.TryGetPrimitiveType(underlyingType, out ptype); if (!knownType) { nestedElementType = this.context.ResolveTypeForMaterialization(type, wireTypeName); Debug.Assert(nestedElementType != null, "nestedElementType != null -- otherwise ReadTypeAttribute (or someone!) should throw"); knownType = PrimitiveType.TryGetPrimitiveType(nestedElementType.ElementType, out ptype); } if (knownType) { if (value == null) { if (!ClientTypeUtil.CanAssignNull(type)) { throw new InvalidOperationException(throwOnNullMessage()); } materializedValue = null; } else { materializedValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(value, underlyingType); } } else { materializedValue = null; } }
/// <summary> /// Write the entry element. /// </summary> /// <param name="entityDescriptor">The entity.</param> /// <param name="relatedLinks">Collection of links related to the entity.</param> /// <param name="requestMessage">The OData request message.</param> internal void WriteEntry(EntityDescriptor entityDescriptor, IEnumerable <LinkDescriptor> relatedLinks, ODataRequestMessageWrapper requestMessage) { ClientEdmModel model = this.requestInfo.Model; ClientTypeAnnotation entityType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType())); using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, false /*isParameterPayload*/)) { ODataWriterWrapper entryWriter = ODataWriterWrapper.CreateForEntry(messageWriter, this.requestInfo.Configurations.RequestPipeline); // Get the server type name using the type resolver or from the entity descriptor string serverTypeName = this.requestInfo.GetServerTypeName(entityDescriptor); var entry = CreateODataEntry(entityDescriptor, serverTypeName, entityType, this.requestInfo.Format); // Add the annotation required for writing the payload into an XElement // for firing WritingEntity events if (this.requestInfo.HasWritingEventHandlers) { entry.SetAnnotation(new WritingEntityInfo(entityDescriptor.Entity, this.requestInfo)); } if (serverTypeName == null) { serverTypeName = this.requestInfo.InferServerTypeNameFromServerModel(entityDescriptor); } entry.Properties = this.propertyConverter.PopulateProperties(entityDescriptor.Entity, serverTypeName, entityType.PropertiesToSerialize()); entryWriter.WriteStart(entry, entityDescriptor.Entity); if (EntityStates.Added == entityDescriptor.State) { this.WriteNavigationLink(entityDescriptor, relatedLinks, entryWriter); } entryWriter.WriteEnd(entry, entityDescriptor.Entity); } }
/// <summary> /// Initializes a new instance of the <see cref="ClientEdmStructuredValue"/> class. /// </summary> /// <param name="structuredValue">The structured value.</param> /// <param name="model">The model.</param> /// <param name="clientTypeAnnotation">The client type annotation.</param> public ClientEdmStructuredValue(object structuredValue, ClientEdmModel model, ClientTypeAnnotation clientTypeAnnotation) { Debug.Assert(structuredValue != null, "entity != null"); Debug.Assert(model != null, "model != null"); Debug.Assert(clientTypeAnnotation != null, "clientTypeAnnotation != null"); if (clientTypeAnnotation.EdmType.TypeKind == EdmTypeKind.Complex) { // TODO: nullable? this.Type = new EdmComplexTypeReference((IEdmComplexType)clientTypeAnnotation.EdmType, true); } else { Debug.Assert(clientTypeAnnotation.EdmType.TypeKind == EdmTypeKind.Entity, "Only complex and entity values supported"); // TODO: nullable? this.Type = new EdmEntityTypeReference((IEdmEntityType)clientTypeAnnotation.EdmType, true); } this.structuredValue = structuredValue; this.typeAnnotation = clientTypeAnnotation; this.model = model; }
/// <summary> /// Gets or creates client type annotation. /// </summary> /// <param name="edmType">The EdmType to use for creating client type annotation</param> /// <param name="type">The Clr type to create client type annotation for.</param> /// <returns>Client type annotation</returns> private ClientTypeAnnotation GetOrCreateClientTypeAnnotation(IEdmType edmType, Type type) { ClientTypeAnnotation clientTypeAnnotation; string qualifiedName = type.ToString(); // all that are not built-in types need to be cached: enum, complex, entity if (edmType.TypeKind == EdmTypeKind.Enum || edmType.TypeKind == EdmTypeKind.Complex || edmType.TypeKind == EdmTypeKind.Entity) { lock (this.typeNameToClientTypeAnnotationCache) { if (this.typeNameToClientTypeAnnotationCache.TryGetValue(qualifiedName, out clientTypeAnnotation) && clientTypeAnnotation.ElementType != type) { qualifiedName = type.AssemblyQualifiedName; if (this.typeNameToClientTypeAnnotationCache.TryGetValue(qualifiedName, out clientTypeAnnotation) && clientTypeAnnotation.ElementType != type) { throw c.Error.InvalidOperation(Strings.ClientType_MultipleTypesWithSameName(qualifiedName)); } } if (clientTypeAnnotation == null) { clientTypeAnnotation = new ClientTypeAnnotation(edmType, type, qualifiedName, this); this.typeNameToClientTypeAnnotationCache.Add(qualifiedName, clientTypeAnnotation); } else { Debug.Assert(clientTypeAnnotation.ElementType == type, "existing clientTypeAnnotation.ElementType == type"); } } } else { clientTypeAnnotation = new ClientTypeAnnotation(edmType, type, qualifiedName, this); } return(clientTypeAnnotation); }
/// <summary> /// Creates instance of EntityPropertyMappingInfo class. /// </summary> /// <param name="attribute">The <see cref="EntityPropertyMappingAttribute"/> corresponding to this object</param> /// <param name="definingType">Type the <see cref="EntityPropertyMappingAttribute"/> was defined on.</param> /// <param name="actualPropertyType">ClientType whose property is to be read.</param> public EntityPropertyMappingInfo(EntityPropertyMappingAttribute attribute, Type definingType, ClientTypeAnnotation actualPropertyType) { #endif Debug.Assert(attribute != null, "attribute != null"); Debug.Assert(definingType != null, "definingType != null"); Debug.Assert(actualPropertyType != null, "actualPropertyType != null"); this.attribute = attribute; this.definingType = definingType; this.actualPropertyType = actualPropertyType; Debug.Assert(!string.IsNullOrEmpty(attribute.SourcePath), "Invalid source path"); this.propertyValuePath = attribute.SourcePath.Split('/'); // Infer the mapping type from the attribute this.isSyndicationMapping = this.attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty; }
private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties) { Debug.Assert(type != null, "type != null"); Debug.Assert(keyProperties != null, "keyProperties != null"); EdmTypeCacheValue cachedEdmType; lock (this.clrToEdmTypeCache) { this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType); } if (cachedEdmType == null) { Type collectionType; if (PrimitiveType.IsKnownNullableType(type)) { PrimitiveType primitiveType; PrimitiveType.TryGetPrimitiveType(type, out primitiveType); Debug.Assert(primitiveType != null, "primitiveType != null"); cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties); } else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null) { // Collection Type Type elementType = collectionType.GetGenericArguments()[0]; IEdmType itemType = this.GetOrCreateEdmTypeInternal(elementType).EdmType; // Note that while collection of a collection is not allowed, we cannot throw here since it's a breaking change. // We will throw during SaveChanges() and we have unit test validating the error case. Debug.Assert( itemType.TypeKind == EdmTypeKind.Entity || itemType.TypeKind == EdmTypeKind.Complex || itemType.TypeKind == EdmTypeKind.Primitive || itemType.TypeKind == EdmTypeKind.Collection, "itemType.TypeKind == EdmTypeKind.Entity || itemType.TypeKind == EdmTypeKind.Complex || itemType.TypeKind == EdmTypeKind.Primitive || itemType.TypeKind == EdmTypeKind.Collection"); cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties); } else { if (isEntity) { Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) => { // Create properties without modifying the entityType. // This will leave entityType intact in case of an exception during loading. List <IEdmProperty> loadedProperties = new List <IEdmProperty>(); List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>(); foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name)) { IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property); loadedProperties.Add(edmProperty); if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name)) { Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural"); Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive"); loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty); } } // Now add properties to the entityType. foreach (IEdmProperty property in loadedProperties) { entityType.AddProperty(property); } entityType.AddKeys(loadedKeyProperties); }; // Creating an entity type Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity"); cachedEdmType = new EdmTypeCacheValue( new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), false /*isOpen*/, delayLoadEntityProperties), hasProperties); } else { Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) => { // Create properties without modifying the complexType. // This will leave complexType intact in case of an exception during loading. List <IEdmProperty> loadedProperties = new List <IEdmProperty>(); foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name)) { IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property); loadedProperties.Add(edmProperty); } // Now add properties to the complexType. foreach (IEdmProperty property in loadedProperties) { complexType.AddProperty(property); } }; // Creating a complex type Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex"); cachedEdmType = new EdmTypeCacheValue( new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), delayLoadComplexProperties), hasProperties); } } Debug.Assert(cachedEdmType != null, "cachedEdmType != null"); IEdmType edmType = cachedEdmType.EdmType; ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type); this.SetClientTypeAnnotation(edmType, clientTypeAnnotation); if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex) { IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType; Debug.Assert(edmStructuredType != null, "edmStructuredType != null"); this.SetMimeTypeForProperties(edmStructuredType); } // Need to cache the type before loading the properties so we don't stack overflow because // loading the property can trigger calls to GetOrCreateEdmType on the same type. lock (this.clrToEdmTypeCache) { EdmTypeCacheValue existing; if (this.clrToEdmTypeCache.TryGetValue(type, out existing)) { cachedEdmType = existing; } else { this.clrToEdmTypeCache.Add(type, cachedEdmType); } } } return(cachedEdmType); }
/// <summary> /// Get the server type name - either from the entity descriptor or using the type resolver. /// </summary> /// <param name="clientTypeAnnotation">Client type annotation.</param> /// <returns>The server type name for the entity.</returns> internal string GetServerTypeName(ClientTypeAnnotation clientTypeAnnotation) { string serverTypeName = this.ResolveNameFromType(clientTypeAnnotation.ElementType); return(serverTypeName); }
/// <summary> /// Convert an instance annotation to clr object. /// </summary> /// <param name="instanceAnnotation">Instance annotation to be converted</param> /// <param name="clrInstanceAnnotation">The clr object</param> /// <returns>A dictionary of clr-typed instance annotation</returns> private bool TryConvertToClrInstanceAnnotation(ODataInstanceAnnotation instanceAnnotation, out object clrInstanceAnnotation) { clrInstanceAnnotation = null; var primitiveValue = instanceAnnotation.Value as ODataPrimitiveValue; if (primitiveValue != null) { clrInstanceAnnotation = primitiveValue.Value; return(true); } var enumValue = instanceAnnotation.Value as ODataEnumValue; if (enumValue != null) { var type = this.MaterializerContext.Context.ResolveTypeFromName(enumValue.TypeName); if (type != null) { clrInstanceAnnotation = EnumValueMaterializationPolicy.MaterializeODataEnumValue(type, enumValue); return(true); } return(false); } var collectionValue = instanceAnnotation.Value as ODataCollectionValue; if (collectionValue != null) { var serverSideModel = this.MaterializerContext.Context.Format.LoadServiceModel(); var valueTerm = serverSideModel.FindTerm(instanceAnnotation.Name); if (valueTerm != null && valueTerm.Type != null && valueTerm.Type.Definition != null) { var edmCollectionType = valueTerm.Type.Definition as IEdmCollectionType; if (edmCollectionType != null) { Type collectionItemType = null; var elementType = edmCollectionType.ElementType; PrimitiveType primitiveType; if (PrimitiveType.TryGetPrimitiveType(elementType.FullName(), out primitiveType)) { collectionItemType = primitiveType.ClrType; } else { collectionItemType = this.MaterializerContext.Context.ResolveTypeFromName(elementType.FullName()); } if (collectionItemType != null) { Type collectionICollectionType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType }); ClientTypeAnnotation collectionClientTypeAnnotation = this.MaterializerContext.ResolveTypeForMaterialization( collectionICollectionType, collectionValue.TypeName); bool isElementNullable = edmCollectionType.ElementType.IsNullable; var collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionInstance( collectionClientTypeAnnotation.EdmTypeReference as IEdmCollectionTypeReference, collectionClientTypeAnnotation.ElementType); this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues( collectionValue.Items, collectionValue.TypeName, collectionInstance, collectionItemType, ClientTypeUtil.GetAddToCollectionDelegate(collectionICollectionType), isElementNullable); clrInstanceAnnotation = collectionInstance; return(true); } } } return(false); } var nullValue = instanceAnnotation.Value as ODataNullValue; if (nullValue != null) { clrInstanceAnnotation = null; return(true); } return(false); }
/// <summary> /// ConstantExpression visit method /// </summary> /// <param name="c">The ConstantExpression expression to visit</param> /// <returns>The visited ConstantExpression expression </returns> internal override Expression VisitConstant(ConstantExpression c) { if (c.Value == null) { this.builder.Append(UriHelper.NULL); return(c); } // DEVNOTE: // Rather than forcing every other codepath to have the 'Try...' pattern for formatting, // we catch the InvalidOperationException here to change the exception type. // This is exceedingly rare, and not a scenario where performance is meaningful, so the // reduced complexity in all other call sites is worth the extra logic here. string result; BinaryExpression b = this.parent as BinaryExpression; MethodCallExpression m = this.parent as MethodCallExpression; if ((b != null && HasEnumInBinaryExpression(b)) || (m != null && m.Method.Name == "HasFlag")) { c = this.ConvertConstantExpressionForEnum(c); ClientEdmModel model = this.context.Model; IEdmType edmType = model.GetOrCreateEdmType(c.Type.IsEnum() ? c.Type : c.Type.GetGenericArguments()[0]); ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType); string typeNameInEdm = this.context.ResolveNameFromTypeInternal(typeAnnotation.ElementType); MemberInfo member = typeAnnotation.ElementType.GetField(c.Value.ToString()); string memberValue = ClientTypeUtil.GetServerDefinedName(member); ODataEnumValue enumValue = new ODataEnumValue(memberValue, typeNameInEdm ?? typeAnnotation.ElementTypeName); result = ODataUriUtils.ConvertToUriLiteral(enumValue, CommonUtil.ConvertToODataVersion(this.uriVersion), null); } else if (m != null && ReflectionUtil.IsSequenceMethod(m.Method, SequenceMethod.Contains)) { StringBuilder listExpr = new StringBuilder(); ODataVersion version = CommonUtil.ConvertToODataVersion(this.uriVersion); foreach (object item in (IEnumerable)c.Value) { if (listExpr.Length != 0) { listExpr.Append(UriHelper.COMMA); } string uriLiteral = ODataUriUtils.ConvertToUriLiteral(item, version); listExpr.Append(uriLiteral); } // Contains cannot be used with an empty static collection if (listExpr.Length == 0) { throw new InvalidOperationException(Strings.ALinq_ContainsNotValidOnEmptyCollection); } listExpr.Insert(0, UriHelper.LEFTPAREN); listExpr.Append(UriHelper.RIGHTPAREN); result = listExpr.ToString(); } else { try { result = LiteralFormatter.ForConstants.Format(c.Value); } catch (InvalidOperationException) { if (this.cantTranslateExpression) { // there's already a problem in the parents. // we should just return here, because caller somewhere up the stack will throw a better exception return(c); } throw new NotSupportedException(Strings.ALinq_CouldNotConvert(c.Value)); } } Debug.Assert(result != null, "result != null"); this.builder.Append(result); return(c); }
private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties) { EdmTypeCacheValue value2; Action <MetadataProviderEdmEntityType> action3 = null; Action <MetadataProviderEdmComplexType> action4 = null; lock (this.clrToEdmTypeCache) { this.clrToEdmTypeCache.TryGetValue(type, out value2); } if (value2 == null) { if (PrimitiveType.IsKnownNullableType(type)) { PrimitiveType type3; PrimitiveType.TryGetPrimitiveType(type, out type3); value2 = new EdmTypeCacheValue(type3.CreateEdmPrimitiveType(), hasProperties); } else { Type type2; if (((type2 = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null) && (ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null)) { Type type4 = type2.GetGenericArguments()[0]; value2 = new EdmTypeCacheValue(new EdmCollectionType(this.GetOrCreateEdmTypeInternal(type4).EdmType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(type4))), hasProperties); } else if (isEntity) { if (action3 == null) { action3 = delegate(MetadataProviderEdmEntityType entityType) { List <IEdmProperty> list = new List <IEdmProperty>(); List <IEdmStructuralProperty> list1 = new List <IEdmStructuralProperty>(); using (IEnumerator <PropertyInfo> enumerator = (from p in ClientTypeUtil.GetPropertiesOnType(type, edmBaseType != null) orderby p.Name select p).GetEnumerator()) { Func <PropertyInfo, bool> predicate = null; while (enumerator.MoveNext()) { PropertyInfo property = enumerator.Current; IEdmProperty item = this.CreateEdmProperty(entityType, property); list.Add(item); if (edmBaseType == null) { if (predicate == null) { predicate = k => (k.DeclaringType == type) && (k.Name == property.Name); } if (keyProperties.Any <PropertyInfo>(predicate)) { list1.Add((IEdmStructuralProperty)item); } } } } foreach (IEdmProperty property2 in list) { entityType.AddProperty(property2); } entityType.AddKeys(list1); }; } Action <MetadataProviderEdmEntityType> propertyLoadAction = action3; value2 = new EdmTypeCacheValue(new MetadataProviderEdmEntityType(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, type.IsAbstract(), false, propertyLoadAction), hasProperties); } else { if (action4 == null) { action4 = delegate(MetadataProviderEdmComplexType complexType) { List <IEdmProperty> list = new List <IEdmProperty>(); foreach (PropertyInfo info in from p in ClientTypeUtil.GetPropertiesOnType(type, edmBaseType != null) orderby p.Name select p) { IEdmProperty item = this.CreateEdmProperty(complexType, info); list.Add(item); } foreach (IEdmProperty property2 in list) { complexType.AddProperty(property2); } }; } Action <MetadataProviderEdmComplexType> action2 = action4; value2 = new EdmTypeCacheValue(new MetadataProviderEdmComplexType(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, type.IsAbstract(), action2), hasProperties); } } IEdmType edmType = value2.EdmType; ClientTypeAnnotation orCreateClientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type); edmType.SetClientTypeAnnotation(orCreateClientTypeAnnotation); if ((edmType.TypeKind == EdmTypeKind.Entity) || (edmType.TypeKind == EdmTypeKind.Complex)) { IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType; this.SetMimeTypeForProperties(edmStructuredType); } lock (this.clrToEdmTypeCache) { EdmTypeCacheValue value3; if (this.clrToEdmTypeCache.TryGetValue(type, out value3)) { return(value3); } this.clrToEdmTypeCache.Add(type, value2); } } return(value2); }
/// <summary> /// Converts the object to ODataValue, the result could be null, the original primitive object, ODataNullValue, /// ODataEnumValue, ODataCollectionValue, ODataResource, ODataEntityReferenceLinks, ODataEntityReferenceLinks, or /// a list of ODataResource. /// </summary> /// <param name="paramName">The name of the <see cref="UriOperationParameter"/>. Used for error reporting.</param> /// <param name="value">The value of the <see cref="UriOperationParameter"/>.</param> /// <param name="needsSpecialEscaping">True if the result need special escaping.</param> /// <param name="useEntityReference">If true, use entity reference, instead of entity to serialize the parameter.</param> /// <returns>The converted result.</returns> private object ConvertToODataValue(string paramName, object value, ref bool needsSpecialEscaping, bool useEntityReference) { Object valueInODataFormat = null; if (value == null) { needsSpecialEscaping = true; } else if (value is ODataNullValue) { valueInODataFormat = value; needsSpecialEscaping = true; } else { ClientEdmModel model = this.requestInfo.Model; IEdmType edmType = model.GetOrCreateEdmType(value.GetType()); Debug.Assert(edmType != null, "edmType != null"); ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType); Debug.Assert(typeAnnotation != null, "typeAnnotation != null"); switch (edmType.TypeKind) { case EdmTypeKind.Primitive: // Client lib internal conversion to support DateTime if (value is DateTime) { valueInODataFormat = PlatformHelper.ConvertDateTimeToDateTimeOffset((DateTime)value); } else { valueInODataFormat = value; } needsSpecialEscaping = true; break; case EdmTypeKind.Enum: string typeNameInEdm = this.requestInfo.GetServerTypeName(model.GetClientTypeAnnotation(edmType)); valueInODataFormat = new ODataEnumValue( ClientTypeUtil.GetEnumValuesString(value.ToString(), typeAnnotation.ElementType), typeNameInEdm ?? typeAnnotation.ElementTypeName); needsSpecialEscaping = true; break; case EdmTypeKind.Collection: IEdmCollectionType edmCollectionType = edmType as IEdmCollectionType; Debug.Assert(edmCollectionType != null, "edmCollectionType != null"); IEdmTypeReference itemTypeReference = edmCollectionType.ElementType; Debug.Assert(itemTypeReference != null, "itemTypeReference != null"); ClientTypeAnnotation itemTypeAnnotation = model.GetClientTypeAnnotation(itemTypeReference.Definition); Debug.Assert(itemTypeAnnotation != null, "itemTypeAnnotation != null"); valueInODataFormat = ConvertToCollectionValue(paramName, value, itemTypeAnnotation, useEntityReference); break; case EdmTypeKind.Complex: case EdmTypeKind.Entity: Debug.Assert(edmType.TypeKind == EdmTypeKind.Complex || value != null, "edmType.TypeKind == EdmTypeKind.Complex || value != null"); Debug.Assert(typeAnnotation != null, "typeAnnotation != null"); valueInODataFormat = ConvertToEntityValue(value, typeAnnotation.ElementType, useEntityReference); break; default: // EdmTypeKind.Row // EdmTypeKind.EntityReference throw new NotSupportedException(Strings.Serializer_InvalidParameterType(paramName, edmType.TypeKind)); } Debug.Assert(valueInODataFormat != null, "valueInODataFormat != null"); } return(valueInODataFormat); }
/// <summary> /// Writes a navigation link. /// </summary> /// <param name="entityDescriptor">The entity</param> /// <param name="relatedLinks">The links related to the entity</param> /// <param name="odataWriter">The ODataWriter used to write the navigation link.</param> internal void WriteNestedResourceInfo(EntityDescriptor entityDescriptor, IEnumerable <LinkDescriptor> relatedLinks, ODataWriterWrapper odataWriter) { // TODO: create instance of odatawriter. // TODO: send clientType once, so that we dont need entity descriptor Debug.Assert(EntityStates.Added == entityDescriptor.State, "entity not added state"); Dictionary <string, List <LinkDescriptor> > groupRelatedLinks = new Dictionary <string, List <LinkDescriptor> >(EqualityComparer <string> .Default); foreach (LinkDescriptor end in relatedLinks) { List <LinkDescriptor> linkDescriptorsList = null; if (!groupRelatedLinks.TryGetValue(end.SourceProperty, out linkDescriptorsList)) { linkDescriptorsList = new List <LinkDescriptor>(); groupRelatedLinks.Add(end.SourceProperty, linkDescriptorsList); } linkDescriptorsList.Add(end); } ClientTypeAnnotation clientType = null; foreach (var grlinks in groupRelatedLinks) { if (null == clientType) { ClientEdmModel model = this.requestInfo.Model; clientType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType())); } bool isCollection = clientType.GetProperty(grlinks.Key, UndeclaredPropertyBehavior.ThrowException).IsEntityCollection; bool started = false; foreach (LinkDescriptor end in grlinks.Value) { Debug.Assert(!end.ContentGeneratedForSave, "already saved link"); end.ContentGeneratedForSave = true; Debug.Assert(null != end.Target, "null is DELETE"); ODataNestedResourceInfo navigationLink = new ODataNestedResourceInfo(); navigationLink.Url = this.requestInfo.EntityTracker.GetEntityDescriptor(end.Target).GetLatestEditLink(); Debug.Assert(Uri.IsWellFormedUriString(UriUtil.UriToString(navigationLink.Url), UriKind.Absolute), "Uri.IsWellFormedUriString(targetEditLink, UriKind.Absolute)"); navigationLink.IsCollection = isCollection; navigationLink.Name = grlinks.Key; if (!started) { odataWriter.WriteNestedResourceInfoStart(navigationLink); started = true; } odataWriter.WriteNestedResourceInfoStart(navigationLink, end.Source, end.Target); odataWriter.WriteEntityReferenceLink(new ODataEntityReferenceLink() { Url = navigationLink.Url }, end.Source, end.Target); odataWriter.WriteNestedResourceInfoEnd(navigationLink, end.Source, end.Target); } odataWriter.WriteNestedResourceInfoEnd(); } }
/// <summary> /// Creates an ODataResource for the given EntityDescriptor and fills in its ODataLib metadata. /// </summary> /// <param name="entityDescriptor">The entity descriptor.</param> /// <param name="serverTypeName">Name of the server type.</param> /// <param name="entityType">The client-side entity type.</param> /// <param name="clientFormat">The current client format.</param> /// <returns>An odata entry with its metadata filled in.</returns> internal static ODataResource CreateODataEntry(EntityDescriptor entityDescriptor, string serverTypeName, ClientTypeAnnotation entityType, DataServiceClientFormat clientFormat) { ODataResource entry = new ODataResource(); // If the client type name is different from the server type name, then add SerializationTypeNameAnnotation // which tells ODataLib to write the type name in the annotation in the payload. if (entityType.ElementTypeName != serverTypeName) { entry.TypeAnnotation = new ODataTypeAnnotation(serverTypeName); } // We always need to write the client type name, since this is the type name used by ODataLib // to resolve the entity type using EdmModel.FindSchemaElement. entry.TypeName = entityType.ElementTypeName; if (entityDescriptor.IsMediaLinkEntry || entityType.IsMediaLinkEntry) { // Since we are already enabled EnableWcfDataServicesClientBehavior in the writer settings, // setting the MediaResource value will tell ODataLib to write MLE payload, irrespective of // what the metadata says. entry.MediaResource = new ODataStreamReferenceValue(); } return(entry); }
private ODataRequestMessageWrapper CheckAndProcessMediaEntryPost(EntityDescriptor entityDescriptor) { ClientEdmModel model = ClientEdmModel.GetModel(base.RequestInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType())); if (!clientTypeAnnotation.IsMediaLinkEntry && !entityDescriptor.IsMediaLinkEntry) { return(null); } if ((clientTypeAnnotation.MediaDataMember == null) && (entityDescriptor.SaveStream == null)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Context_MLEWithoutSaveStream(clientTypeAnnotation.ElementTypeName)); } ODataRequestMessageWrapper mediaResourceRequest = null; if (clientTypeAnnotation.MediaDataMember != null) { string contentType = null; int length = 0; if (clientTypeAnnotation.MediaDataMember.MimeTypeProperty == null) { contentType = "application/octet-stream"; } else { object obj2 = clientTypeAnnotation.MediaDataMember.MimeTypeProperty.GetValue(entityDescriptor.Entity); string str2 = (obj2 != null) ? obj2.ToString() : null; if (string.IsNullOrEmpty(str2)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Context_NoContentTypeForMediaLink(clientTypeAnnotation.ElementTypeName, clientTypeAnnotation.MediaDataMember.MimeTypeProperty.PropertyName)); } contentType = str2; } object propertyValue = clientTypeAnnotation.MediaDataMember.GetValue(entityDescriptor.Entity); if (propertyValue == null) { base.mediaResourceRequestStream = null; } else { byte[] bytes = propertyValue as byte[]; if (bytes == null) { string str3; Encoding encoding; HttpProcessUtility.ReadContentType(contentType, out str3, out encoding); if (encoding == null) { encoding = Encoding.UTF8; contentType = contentType + ";charset=UTF-8"; } bytes = encoding.GetBytes(ClientConvert.ToString(propertyValue)); } length = bytes.Length; base.mediaResourceRequestStream = new MemoryStream(bytes, 0, bytes.Length, false, true); } mediaResourceRequest = this.CreateMediaResourceRequest(entityDescriptor.GetResourceUri(base.RequestInfo.BaseUriResolver, false), "POST", Util.DataServiceVersion1, clientTypeAnnotation.MediaDataMember == null, true); mediaResourceRequest.SetHeader("Content-Length", length.ToString(CultureInfo.InvariantCulture)); mediaResourceRequest.SetHeader("Content-Type", contentType); mediaResourceRequest.AddHeadersToReset("Content-Length"); mediaResourceRequest.AddHeadersToReset("Content-Type"); } else { mediaResourceRequest = this.CreateMediaResourceRequest(entityDescriptor.GetResourceUri(base.RequestInfo.BaseUriResolver, false), "POST", Util.DataServiceVersion1, clientTypeAnnotation.MediaDataMember == null, true); this.SetupMediaResourceRequest(mediaResourceRequest, entityDescriptor.SaveStream, null); } entityDescriptor.State = EntityStates.Modified; return(mediaResourceRequest); }
public void Init() { this.serverModel = new EdmModel(); this.serverEntityType = new EdmEntityType("Server.NS", "ServerEntityType"); this.serverEntityTypeName = "Server.NS.ServerEntityType"; this.serverModel.AddElement(this.serverEntityType); this.serverEntityType.AddKeys(this.serverEntityType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); var addressType = new EdmComplexType("Server.NS", "Address"); addressType.AddStructuralProperty("Street", EdmPrimitiveTypeKind.String); this.serverEntityType.AddStructuralProperty("Address", new EdmComplexTypeReference(addressType, true)); this.serverComplexTypeName = "Server.NS.Address"; var homeAddressType = new EdmComplexType("Server.NS", "HomeAddress", addressType); homeAddressType.AddStructuralProperty("FamilyName", EdmPrimitiveTypeKind.String); this.serverComplexTypeName = "Server.NS.HomeAddress"; var colorType = new EdmEnumType("Server.NS", "Color"); colorType.AddMember(new EdmEnumMember(colorType, "Red", new EdmEnumMemberValue(1))); colorType.AddMember(new EdmEnumMember(colorType, "Blue", new EdmEnumMemberValue(2))); colorType.AddMember(new EdmEnumMember(colorType, "Green", new EdmEnumMemberValue(3))); this.serverEntityType.AddStructuralProperty("Color", new EdmEnumTypeReference(colorType, false)); this.serverEntityType.AddStructuralProperty("Nicknames", new EdmCollectionTypeReference(new EdmCollectionType(EdmCoreModel.Instance.GetInt32(false)))); this.serverEntityType.AddStructuralProperty("OtherAddresses", new EdmCollectionTypeReference(new EdmCollectionType(new EdmComplexTypeReference(addressType, false)))); this.clientModel = new ClientEdmModel(ODataProtocolVersion.V4); this.clientTypeAnnotation = this.clientModel.GetClientTypeAnnotation(typeof(TestClientEntityType)); this.context = new DataServiceContext(new Uri("http://temp/"), ODataProtocolVersion.V4, this.clientModel); this.context.Format.UseJson(this.serverModel); this.testSubject = new ODataPropertyConverter(new RequestInfo(this.context)); this.context.Format.UseJson(this.serverModel); this.context.ResolveName = t => { if (t == typeof(TestClientEntityType)) { return(this.serverEntityTypeName); } if (t == typeof(Address)) { return(this.serverComplexTypeName); } return(null); }; this.entity = new TestClientEntityType { Id = 1, Name = "foo", Number = 1.23f, Address = new Address(), OpenAddress = new Address(), Nicknames = new string[0], OtherAddresses = new[] { new Address() }, Color = 0 }; this.entityWithDerivedComplexProperty = new TestClientEntityType { Id = 1, Name = "foo", Number = 1.23f, Address = new HomeAddress(), OpenAddress = new Address(), Nicknames = new string[0], OtherAddresses = new[] { new Address() } }; this.entityWithDerivedComplexInCollection = new TestClientEntityType { Id = 1, Name = "foo", Number = 1.23f, Address = new HomeAddress(), OpenAddress = new Address(), Nicknames = new string[0], OtherAddresses = new[] { new Address(), new HomeAddress() } }; }
/// <summary> /// Applies the collection data values to a collection instance. /// </summary> /// <param name="items">The items.</param> /// <param name="wireTypeName">Name of the wire type.</param> /// <param name="collectionInstance">The collection instance.</param> /// <param name="collectionItemType">Type of the collection item.</param> /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param> /// <param name="isElementNullable">If element type is nullable.</param> internal void ApplyCollectionDataValues( IEnumerable items, string wireTypeName, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance, bool isElementNullable) { Debug.Assert(collectionInstance != null, "collectionInstance != null"); Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue"); Debug.Assert(collectionItemType.IsAssignableFrom( ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0]), "collectionItemType has to match the collectionInstance generic type."); Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities"); Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null"); // is the Collection not empty ? if (items != null) { bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType); foreach (object item in items) { if (!isElementNullable && item == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported); } ODataComplexValue complexValue = item as ODataComplexValue; ODataEnumValue enumVal = null; // Is it a Collection of primitive types? if (isCollectionItemTypePrimitive) { // verify that the Collection does not contain complex type items if (complexValue != null || item is ODataCollectionValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed); } object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item); addValueToBackingICollectionInstance(collectionInstance, materializedValue); } else if ((enumVal = item as ODataEnumValue) != null) { // TODO: use EnumValueMaterializationPolicy.MaterializeEnumDataValueCollectionElement() here object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(collectionItemType, enumVal); addValueToBackingICollectionInstance(collectionInstance, tmpValue); } else { // verify that the Collection does not contain primitive values if (item != null && complexValue == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); } if (item != null) { ClientTypeAnnotation complexType = this.materializerContext.ResolveTypeForMaterialization(collectionItemType, complexValue.TypeName); object complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType); // set properties with metarialized data values if there are any (note that for a payload that looks as follows <element xmlns="http://docs.oasis-open.org/odata/ns/data"/> // and represents an item that is a complex type there are no properties to be set) this.ComplexValueMaterializationPolicy.ApplyDataValues(complexType, complexValue.Properties, complexInstance); addValueToBackingICollectionInstance(collectionInstance, complexInstance); // Apply instance annotation for complex type item if (!this.materializerContext.Context.DisableInstanceAnnotationMaterialization) { this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(complexValue, complexInstance); } } else { addValueToBackingICollectionInstance(collectionInstance, null); } } } } }
/// <summary> /// Gets the CLR value of a term that has been applied to the specified object /// </summary> /// <typeparam name="TResult">The CLR type of the annotation to be returned.</typeparam> /// <param name="context">The data service context.</param> /// <param name="source">The specified annotated object instance.</param> /// <param name="term">The term name.</param> /// <param name="qualifier">The qualifier name.</param> /// <param name="annotationValue">Value of the term evaluated.</param> /// <returns>True if the annotation value can be evaluated, else false.</returns> internal static bool TryGetMetadataAnnotation <TResult>(DataServiceContext context, object source, string term, string qualifier, out TResult annotationValue) { IEdmVocabularyAnnotation edmValueAnnotation = null; ClientEdmStructuredValue clientEdmValue = null; PropertyInfo propertyInfo = null; MethodInfo methodInfo = null; var keyValue = source as Tuple <object, MemberInfo>; if (keyValue != null) { // Get metadata annotation defined on property or Navigation property or Operation or OperationImport var instance = keyValue.Item1; var memberInfo = keyValue.Item2; propertyInfo = memberInfo as PropertyInfo; methodInfo = memberInfo as MethodInfo; if (instance != null) { IEdmType edmType = context.Model.GetOrCreateEdmType(instance.GetType()); if (edmType is IEdmStructuredType) { ClientTypeAnnotation clientTypeAnnotation = context.Model.GetClientTypeAnnotation(edmType); clientEdmValue = new ClientEdmStructuredValue(instance, context.Model, clientTypeAnnotation); } } } else { if (propertyInfo == null) { propertyInfo = source as PropertyInfo; } if (methodInfo == null) { methodInfo = source as MethodInfo; } } if (propertyInfo != null) { edmValueAnnotation = GetOrInsertCachedMetadataAnnotationForPropertyInfo(context, propertyInfo, term, qualifier); return(TryEvaluateMetadataAnnotation(context, edmValueAnnotation, clientEdmValue, out annotationValue)); } if (methodInfo != null) { edmValueAnnotation = GetOrInsertCachedMetadataAnnotationForMethodInfo(context, methodInfo, term, qualifier); return(TryEvaluateMetadataAnnotation(context, edmValueAnnotation, clientEdmValue, out annotationValue)); } var type = source as Type; Type underlyingType = type; if (type == null) { type = source.GetType(); underlyingType = Nullable.GetUnderlyingType(type) ?? type; // For complex type or entity type instance, try to convert the instance to ClientEdmStructuredValue for further evaluation. IEdmType edmType = context.Model.GetOrCreateEdmType(underlyingType); if (edmType is IEdmStructuredType) { ClientTypeAnnotation clientTypeAnnotation = context.Model.GetClientTypeAnnotation(edmType); clientEdmValue = new ClientEdmStructuredValue(source, context.Model, clientTypeAnnotation); } } edmValueAnnotation = GetOrInsertCachedMetadataAnnotationForType(context, underlyingType, term, qualifier); return(TryEvaluateMetadataAnnotation(context, edmValueAnnotation, clientEdmValue, out annotationValue)); }
private string ConvertToEscapedUriValue(string paramName, object value) { object obj2 = null; string str; bool flag = false; if (value == null) { flag = true; } else if (value.GetType() == typeof(ODataUriNullValue)) { obj2 = value; flag = true; } else { ClientTypeAnnotation annotation3; ClientEdmModel model = ClientEdmModel.GetModel(this.requestInfo.MaxProtocolVersion); IEdmType orCreateEdmType = model.GetOrCreateEdmType(value.GetType()); switch (orCreateEdmType.TypeKind) { case EdmTypeKind.Primitive: obj2 = value; flag = true; goto Label_0155; case EdmTypeKind.Complex: { ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(orCreateEdmType); obj2 = this.CreateODataComplexValue(clientTypeAnnotation.ElementType, value, null, false, null); SerializationTypeNameAnnotation annotation = ((ODataComplexValue)obj2).GetAnnotation <SerializationTypeNameAnnotation>(); if ((annotation == null) || string.IsNullOrEmpty(annotation.TypeName)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.DataServiceException_GeneralError); } goto Label_0155; } case EdmTypeKind.Collection: { IEdmCollectionType type2 = orCreateEdmType as IEdmCollectionType; IEdmTypeReference elementType = type2.ElementType; annotation3 = model.GetClientTypeAnnotation(elementType.Definition); switch (annotation3.EdmType.TypeKind) { case EdmTypeKind.Primitive: case EdmTypeKind.Complex: obj2 = this.CreateODataCollection(annotation3.ElementType, null, value, null); goto Label_0155; } break; } default: throw new NotSupportedException(System.Data.Services.Client.Strings.Serializer_InvalidParameterType(paramName, orCreateEdmType.TypeKind)); } throw new NotSupportedException(System.Data.Services.Client.Strings.Serializer_InvalidCollectionParamterItemType(paramName, annotation3.EdmType.TypeKind)); } Label_0155: str = ODataUriUtils.ConvertToUriLiteral(obj2, CommonUtil.ConvertToODataVersion(this.requestInfo.MaxProtocolVersionAsVersion)); if (flag) { return(DataStringEscapeBuilder.EscapeDataString(str)); } return(Uri.EscapeDataString(str)); }
/// <summary>Applies a data value to the specified <paramref name="instance"/>.</summary> /// <param name="type">Type to which a property value will be applied.</param> /// <param name="property">Property with value to apply.</param> /// <param name="instance">Instance on which value will be applied.</param> internal void ApplyDataValue(ClientTypeAnnotation type, ODataProperty property, object instance) { Debug.Assert(type != null, "type != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(instance != null, "instance != null"); var prop = type.GetProperty(property.Name, this.MaterializerContext.IgnoreMissingProperties); if (prop == null) { return; } // Is it a collection? (note: property.Properties will be null if the Collection is empty (contains no elements)) Type enumTypeTmp = null; if (prop.IsPrimitiveOrEnumOrComplexCollection) { // Collections must not be null if (property.Value == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionNotSupported(property.Name)); } // This happens if the payload contain just primitive value for a Collection property if (property.Value is string) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MixedTextWithComment); } if (property.Value is ODataComplexValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidCollectionItem(property.Name)); } // ODataLib already parsed the data and materialized all the primitive types. There is nothing more to materialize // anymore. Only complex type instance and collection instances need to be materialized, but those will be // materialized later on. // We need to materialize items before we change collectionInstance since this may throw. If we tried materializing // after the Collection is wiped or created we would leave the object in half constructed state. object collectionInstance = prop.GetValue(instance); if (collectionInstance == null) { collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, prop.PropertyType); // allowAdd is false - we need to assign instance as the new property value prop.SetValue(instance, collectionInstance, property.Name, false /* allowAdd? */); } else { // Clear existing Collection prop.ClearBackingICollectionInstance(collectionInstance); } bool isElementNullable = prop.EdmProperty.Type.AsCollection().ElementType().IsNullable; this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues( property, collectionInstance, prop.PrimitiveOrComplexCollectionItemType, prop.AddValueToBackingICollectionInstance, isElementNullable); } else if ((enumTypeTmp = Nullable.GetUnderlyingType(prop.NullablePropertyType) ?? prop.NullablePropertyType) != null && enumTypeTmp.IsEnum) { ODataEnumValue enumValue = property.Value as ODataEnumValue; object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(enumTypeTmp, enumValue); // TODO: 1. use EnumValueMaterializationPolicy 2. handle nullable enum property prop.SetValue(instance, tmpValue, property.Name, false /* allowAdd? */); } else { object propertyValue = property.Value; ODataComplexValue complexValue = propertyValue as ODataComplexValue; if (propertyValue != null && complexValue != null) { if (!prop.EdmProperty.Type.IsComplex()) { // The error message is a bit odd, but it's compatible with V1. throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_ExpectingSimpleValue); } // Complex type. bool needToSet = false; ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(prop.PropertyType)); object complexInstance = prop.GetValue(instance); // Validating property inheritance in complexvalue and instance if (prop.PropertyType.Name != property.Name) { complexType = this.MaterializerContext.ResolveTypeForMaterialization(prop.PropertyType, complexValue.TypeName); // recreate complexInstance with derived type complexInstance = null; } if (complexValue.Properties.Any() || complexInstance == null) { complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType); needToSet = true; } this.MaterializeDataValues(complexType, complexValue.Properties, this.MaterializerContext.IgnoreMissingProperties); this.ApplyDataValues(complexType, complexValue.Properties, complexInstance); if (needToSet) { prop.SetValue(instance, complexInstance, property.Name, true /* allowAdd? */); } } else { this.MaterializePrimitiveDataValue(prop.NullablePropertyType, property); prop.SetValue(instance, property.GetMaterializedValue(), property.Name, true /* allowAdd? */); } } }
private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties) { Debug.Assert(type != null, "type != null"); Debug.Assert(keyProperties != null, "keyProperties != null"); EdmTypeCacheValue cachedEdmType; lock (this.clrToEdmTypeCache) { this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType); } if (cachedEdmType == null) { Type collectionType; if (PrimitiveType.IsKnownNullableType(type)) { PrimitiveType primitiveType; PrimitiveType.TryGetPrimitiveType(type, out primitiveType); Debug.Assert(primitiveType != null, "primitiveType != null"); cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties); } else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null) { // Collection Type Type elementType = collectionType.GetGenericArguments()[0]; IEdmType itemType = this.GetOrCreateEdmType(elementType); // Note that // 1. throw here because collection of a collection is not allowed // 2. will also throw during SaveChanges(), validated by unit test case 'SerializationOfCollection'in CollectionTests.cs. if ((itemType.TypeKind == EdmTypeKind.Collection)) { throw new ODataException(Strings.ClientType_CollectionOfCollectionNotSupported); } cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties); } else { Type enumTypeTmp = null; if (isEntity) { Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) => { // Create properties without modifying the entityType. // This will leave entityType intact in case of an exception during loading. List <IEdmProperty> loadedProperties = new List <IEdmProperty>(); List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>(); foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name)) { IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property); loadedProperties.Add(edmProperty); if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name)) { Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural"); Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive"); loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty); } } // Now add properties to the entityType. foreach (IEdmProperty property in loadedProperties) { entityType.AddProperty(property); } entityType.AddKeys(loadedKeyProperties); }; // Creating an entity type Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity"); bool hasStream = GetHasStreamValue((IEdmEntityType)edmBaseType, type); cachedEdmType = new EdmTypeCacheValue( new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), /*isOpen*/ false, hasStream, delayLoadEntityProperties), hasProperties); } else if ((enumTypeTmp = Nullable.GetUnderlyingType(type) ?? type) != null && enumTypeTmp.IsEnum()) { Action <EdmEnumTypeWithDelayLoadedMembers> delayLoadEnumMembers = (enumType) => { #if WINRT foreach (FieldInfo tmp in enumTypeTmp.GetFields().Where(fieldInfo => fieldInfo.IsStatic)) #else foreach (FieldInfo tmp in enumTypeTmp.GetFields(BindingFlags.Static | BindingFlags.Public)) #endif { object memberValue = Enum.Parse(enumTypeTmp, tmp.Name, false); enumType.AddMember(new EdmEnumMember(enumType, tmp.Name, new EdmIntegerConstant((long)Convert.ChangeType(memberValue, typeof(long), CultureInfo.InvariantCulture.NumberFormat)))); } }; // underlying type may be Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32, or Edm.Int64. Type underlyingType = Enum.GetUnderlyingType(enumTypeTmp); IEdmPrimitiveType underlyingEdmType = (IEdmPrimitiveType)EdmCoreModel.Instance.FindDeclaredType("Edm." + underlyingType.Name); Debug.Assert(underlyingEdmType != null, "underlyingEdmType != null"); bool isFlags = enumTypeTmp.GetCustomAttributes(false).Any(s => s is FlagsAttribute); cachedEdmType = new EdmTypeCacheValue( new EdmEnumTypeWithDelayLoadedMembers(CommonUtil.GetModelTypeNamespace(enumTypeTmp), CommonUtil.GetModelTypeName(enumTypeTmp), underlyingEdmType, isFlags, delayLoadEnumMembers), null); } else { Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) => { // Create properties without modifying the complexType. // This will leave complexType intact in case of an exception during loading. List <IEdmProperty> loadedProperties = new List <IEdmProperty>(); foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name)) { IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property); loadedProperties.Add(edmProperty); } // Now add properties to the complexType. foreach (IEdmProperty property in loadedProperties) { complexType.AddProperty(property); } }; // Creating a complex type Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex"); cachedEdmType = new EdmTypeCacheValue( new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), /*isOpen*/ false, delayLoadComplexProperties), hasProperties); } } Debug.Assert(cachedEdmType != null, "cachedEdmType != null"); IEdmType edmType = cachedEdmType.EdmType; ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type); this.SetClientTypeAnnotation(edmType, clientTypeAnnotation); if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex) { IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType; Debug.Assert(edmStructuredType != null, "edmStructuredType != null"); this.SetMimeTypeForProperties(edmStructuredType); } // Need to cache the type before loading the properties so we don't stack overflow because // loading the property can trigger calls to GetOrCreateEdmType on the same type. lock (this.clrToEdmTypeCache) { EdmTypeCacheValue existing; if (this.clrToEdmTypeCache.TryGetValue(type, out existing)) { cachedEdmType = existing; } else { this.clrToEdmTypeCache.Add(type, cachedEdmType); } } } return(cachedEdmType); }
/// <summary>Applies a data value to the specified <paramref name="instance"/>.</summary> /// <param name="type">Type to which a property value will be applied.</param> /// <param name="property">Property with value to apply.</param> /// <param name="instance">Instance on which value will be applied.</param> internal void ApplyDataValue(ClientTypeAnnotation type, ODataProperty property, object instance) { Debug.Assert(type != null, "type != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(instance != null, "instance != null"); var prop = type.GetProperty(property.Name, this.MaterializerContext.UndeclaredPropertyBehavior); if (prop == null) { return; } // Is it a collection? (note: property.Properties will be null if the Collection is empty (contains no elements)) Type enumTypeTmp = null; if (prop.IsPrimitiveOrEnumOrComplexCollection) { // Collections must not be null if (property.Value == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionNotSupported(property.Name)); } // This happens if the payload contain just primitive value for a Collection property if (property.Value is string) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MixedTextWithComment); } // ODataLib already parsed the data and materialized all the primitive types. There is nothing more to materialize // anymore. Only complex type instance and collection instances need to be materialized, but those will be // materialized later on. // We need to materialize items before we change collectionInstance since this may throw. If we tried materializing // after the Collection is wiped or created we would leave the object in half constructed state. object collectionInstance = prop.GetValue(instance); if (collectionInstance == null) { collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, prop.PropertyType); // allowAdd is false - we need to assign instance as the new property value prop.SetValue(instance, collectionInstance, property.Name, false /* allowAdd? */); } else { // Clear existing Collection prop.ClearBackingICollectionInstance(collectionInstance); } bool isElementNullable = prop.EdmProperty.Type.AsCollection().ElementType().IsNullable; this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues( property, collectionInstance, prop.PrimitiveOrComplexCollectionItemType, prop.AddValueToBackingICollectionInstance, isElementNullable); } else if ((enumTypeTmp = Nullable.GetUnderlyingType(prop.NullablePropertyType) ?? prop.NullablePropertyType) != null && enumTypeTmp.IsEnum()) { ODataEnumValue enumValue = property.Value as ODataEnumValue; object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(enumTypeTmp, enumValue); // TODO: 1. use EnumValueMaterializationPolicy 2. handle nullable enum property prop.SetValue(instance, tmpValue, property.Name, false /* allowAdd? */); } else { this.MaterializePrimitiveDataValue(prop.NullablePropertyType, property); prop.SetValue(instance, property.GetMaterializedValue(), property.Name, true /* allowAdd? */); } if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization) { // Apply instance annotation for Property this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(property, type.ElementType, instance); } }
/// <summary>Materializes the specified <paramref name="entry"/>.</summary> /// <param name="entry">Entry with object to materialize.</param> /// <param name="includeLinks">Whether links that are expanded for navigation property should be materialized.</param> /// <remarks>This is a payload-driven materialization process.</remarks> private void MaterializeResolvedEntry(MaterializerEntry entry, bool includeLinks) { Debug.Assert(entry.Entry != null, "entry != null"); Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise not resolved/created!"); ClientTypeAnnotation actualType = entry.ActualType; // While materializing entities, we need to make sure the payload that came in the wire is also an entity. // Otherwise we need to fail. // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa if (!actualType.IsStructuredType) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(actualType.ElementTypeName)); } // Note that even if ShouldUpdateFromPayload is false, we will still be creating // nested instances (but not their links), so they show up in the data context // entries. This keeps this code compatible with V1 behavior. this.MaterializeDataValues(actualType, entry.Properties, this.MaterializerContext.UndeclaredPropertyBehavior); if (entry.NestedResourceInfos?.Any() == true) { foreach (ODataNestedResourceInfo link in entry.NestedResourceInfos) { var prop = actualType.GetProperty(link.Name, UndeclaredPropertyBehavior.Support); if (prop != null) { ValidatePropertyMatch(prop, link, this.MaterializerContext.Model, true /*performEntityCheck*/); } } foreach (ODataNestedResourceInfo link in entry.NestedResourceInfos) { MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link); if (linkState == null) { continue; } var prop = actualType.GetProperty(link.Name, this.MaterializerContext.UndeclaredPropertyBehavior); if (prop == null) { if (entry.ShouldUpdateFromPayload) { this.MaterializeDynamicProperty(entry, link); } continue; } // includeLinks is for Navigation property, so we should handle complex property when includeLinks equals false; if (!includeLinks && (prop.IsEntityCollection || prop.EntityCollectionItemType != null)) { continue; } if (linkState.Feed != null) { this.ApplyFeedToCollection(entry, prop, linkState.Feed, includeLinks); } else if (linkState.Entry != null) { MaterializerEntry linkEntry = linkState.Entry; if (linkEntry.Entry != null) { this.Materialize(linkEntry, prop.PropertyType, includeLinks); } if (entry.ShouldUpdateFromPayload) { prop.SetValue(entry.ResolvedObject, linkEntry.ResolvedObject, link.Name, true /* allowAdd? */); if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization && linkEntry.ShouldUpdateFromPayload) { // Apply instance annotation for navigation property this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations( prop.PropertyName, linkEntry.Entry, entry.ActualType.ElementType, entry.ResolvedObject); // Apply instance annotation for entity of the navigation property this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(linkEntry.Entry, linkEntry.ResolvedObject); } this.EntityTrackingAdapter.MaterializationLog.SetLink(entry, prop.PropertyName, linkEntry.ResolvedObject); } } } } foreach (var e in entry.Properties) { if (e.Value is ODataStreamReferenceValue) { continue; } var prop = actualType.GetProperty(e.Name, this.MaterializerContext.UndeclaredPropertyBehavior); if (prop == null) { if (entry.ShouldUpdateFromPayload) { this.MaterializeDynamicProperty(e, entry.ResolvedObject); } continue; } if (entry.ShouldUpdateFromPayload) { ValidatePropertyMatch(prop, e, this.MaterializerContext.Model, true /*performEntityCheck*/); this.ApplyDataValue(actualType, e, entry.ResolvedObject); } } // apply link values if present ApplyLinkProperties(actualType, entry); Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise we didn't do any useful work"); BaseEntityType entity = entry.ResolvedObject as BaseEntityType; if (entity != null) { entity.Context = this.EntityTrackingAdapter.Context; if (!entry.IsTracking) { int? streamDescriptorsCount = entry.EntityDescriptor.StreamDescriptors?.Count; IEdmEntityType entityType = this.EntityTrackingAdapter.Model.FindDeclaredType(entry.Entry.TypeName) as IEdmEntityType; if (streamDescriptorsCount > 0 || entityType?.HasStream == true) { entity.EntityDescriptor = entry.EntityDescriptor; } } } this.MaterializerContext.ResponsePipeline.FireEndEntryEvents(entry); }
private void MaterializeResolvedEntry(MaterializerEntry entry, bool includeLinks) { ClientTypeAnnotation actualType = entry.ActualType; if (!actualType.IsEntityType) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidNonEntityType(actualType.ElementTypeName)); } ODataMaterializer.MaterializeDataValues(actualType, entry.Properties, base.ResponseInfo.IgnoreMissingProperties); if (entry.NavigationLinks != null) { foreach (ODataNavigationLink link in entry.NavigationLinks) { ClientPropertyAnnotation annotation2 = actualType.GetProperty(link.Name, true); if (annotation2 != null) { ValidatePropertyMatch(annotation2, link, base.ResponseInfo, true); } } } if (includeLinks && (entry.NavigationLinks != null)) { foreach (ODataNavigationLink link2 in entry.NavigationLinks) { MaterializerNavigationLink link3 = MaterializerNavigationLink.GetLink(link2); if (link3 != null) { ClientPropertyAnnotation annotation3 = actualType.GetProperty(link2.Name, base.ResponseInfo.IgnoreMissingProperties); if (annotation3 != null) { if (link3.Feed != null) { this.ApplyFeedToCollection(entry, annotation3, link3.Feed, includeLinks); } else if (link3.Entry != null) { MaterializerEntry entry2 = link3.Entry; if (entry2.Entry != null) { this.Materialize(entry2, annotation3.PropertyType, includeLinks); } if (entry.ShouldUpdateFromPayload) { annotation3.SetValue(entry.ResolvedObject, entry2.ResolvedObject, link2.Name, true); this.log.SetLink(entry, annotation3.PropertyName, entry2.ResolvedObject); } } } } } } foreach (ODataProperty property in entry.Properties) { if (!(property.Value is ODataStreamReferenceValue)) { ClientPropertyAnnotation annotation4 = actualType.GetProperty(property.Name, base.ResponseInfo.IgnoreMissingProperties); if ((annotation4 != null) && entry.ShouldUpdateFromPayload) { ValidatePropertyMatch(annotation4, property, base.ResponseInfo, true); ODataMaterializer.ApplyDataValue(actualType, property, base.ResponseInfo.IgnoreMissingProperties, base.ResponseInfo, entry.ResolvedObject); } } } ApplyLinkProperties(actualType, entry); if (base.ResponseInfo.HasReadingEntityHandlers) { ODataMaterializer.ReadingEntityInfo annotation = entry.Entry.GetAnnotation <ODataMaterializer.ReadingEntityInfo>(); base.ResponseInfo.FireReadingEntityEvent(entry.ResolvedObject, annotation.EntryPayload, annotation.BaseUri); } }
/// <summary> /// Generate the batch request for all changes to save. /// </summary> /// <returns>Returns the instance of ODataRequestMessage containing all the headers and payload for the batch request.</returns> private ODataRequestMessageWrapper GenerateBatchRequest() { if (this.ChangedEntries.Count == 0 && this.Queries == null) { this.SetCompleted(); return(null); } ODataRequestMessageWrapper batchRequestMessage = this.CreateBatchRequest(); // we need to fire request after the headers have been written, but before we write the payload batchRequestMessage.FireSendingRequest2(null); using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(batchRequestMessage, this.RequestInfo, false /*isParameterPayload*/)) { this.batchWriter = messageWriter.CreateODataBatchWriter(); this.batchWriter.WriteStartBatch(); if (this.Queries != null) { foreach (DataServiceRequest query in this.Queries) { QueryComponents queryComponents = query.QueryComponents(this.RequestInfo.Model); Uri requestUri = this.RequestInfo.BaseUriResolver.GetOrCreateAbsoluteUri(queryComponents.Uri); Debug.Assert(requestUri != null, "request uri is null"); Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); HeaderCollection headers = new HeaderCollection(); headers.SetRequestVersion(queryComponents.Version, this.RequestInfo.MaxProtocolVersionAsVersion); this.RequestInfo.Format.SetRequestAcceptHeaderForQuery(headers, queryComponents); ODataRequestMessageWrapper batchOperationRequestMessage = this.CreateRequestMessage(XmlConstants.HttpMethodGet, requestUri, headers, this.RequestInfo.HttpStack, null /*descriptor*/, null /*contentId*/); batchOperationRequestMessage.FireSendingEventHandlers(null /*descriptor*/); } } else if (0 < this.ChangedEntries.Count) { if (Util.IsBatchWithSingleChangeset(this.Options)) { this.batchWriter.WriteStartChangeset(); } var model = this.RequestInfo.Model; for (int i = 0; i < this.ChangedEntries.Count; ++i) { if (Util.IsBatchWithIndependentOperations(this.Options)) { this.batchWriter.WriteStartChangeset(); } Descriptor descriptor = this.ChangedEntries[i]; if (descriptor.ContentGeneratedForSave) { continue; } EntityDescriptor entityDescriptor = descriptor as EntityDescriptor; if (descriptor.DescriptorKind == DescriptorKind.Entity) { if (entityDescriptor.State == EntityStates.Added) { // We don't support adding MLE/MR in batch mode ClientTypeAnnotation type = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType())); if (type.IsMediaLinkEntry || entityDescriptor.IsMediaLinkEntry) { throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink); } } else if (entityDescriptor.State == EntityStates.Unchanged || entityDescriptor.State == EntityStates.Modified) { // We don't support PUT for the MR in batch mode // It's OK to PUT the MLE alone inside a batch mode though if (entityDescriptor.SaveStream != null) { throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink); } } } else if (descriptor.DescriptorKind == DescriptorKind.NamedStream) { // Similar to MR, we do not support adding named streams in batch mode. throw Error.NotSupported(Strings.Context_BatchNotSupportedForNamedStreams); } ODataRequestMessageWrapper operationRequestMessage; if (descriptor.DescriptorKind == DescriptorKind.Entity) { operationRequestMessage = this.CreateRequest(entityDescriptor); } else { operationRequestMessage = this.CreateRequest((LinkDescriptor)descriptor); } // we need to fire request after the headers have been written, but before we write the payload operationRequestMessage.FireSendingRequest2(descriptor); this.CreateChangeData(i, operationRequestMessage); if (Util.IsBatchWithIndependentOperations(this.Options)) { this.batchWriter.WriteEndChangeset(); } } if (Util.IsBatchWithSingleChangeset(this.Options)) { this.batchWriter.WriteEndChangeset(); } } this.batchWriter.WriteEndBatch(); this.batchWriter.Flush(); } Debug.Assert(this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generated content for all entities/links"); return(batchRequestMessage); }
private void ResolveByCreating(MaterializerEntry entry, Type expectedEntryType) { ClientTypeAnnotation annotation = base.ResponseInfo.TypeResolver.ResolveEdmTypeName(expectedEntryType, entry.Entry.TypeName); this.ResolveByCreatingWithType(entry, annotation.ElementType); }