コード例 #1
0
 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);
                 }
             }
         }
     }
 }
コード例 #2
0
        /// <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);
        }
コード例 #3
0
        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);
            }
        }
コード例 #4
0
        /// <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*/);
                    }
                }
            }
        }
コード例 #5
0
        /// <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);
            }
        }
コード例 #6
0
        /// <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;
            }
        }
コード例 #7
0
ファイル: Serializer.cs プロジェクト: tapika/swupd
        /// <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);
            }
        }
コード例 #8
0
        /// <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;
        }
コード例 #9
0
ファイル: ClientEdmModel.cs プロジェクト: zdzislaw/odata.net
        /// <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);
        }
コード例 #10
0
        /// <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;
        }
コード例 #11
0
        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);
        }
コード例 #12
0
ファイル: RequestInfo.cs プロジェクト: pbvs/odata.net
        /// <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);
        }
コード例 #13
0
        /// <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);
        }
コード例 #14
0
ファイル: ExpressionWriter.cs プロジェクト: pbvs/odata.net
        /// <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);
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        /// <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);
        }
コード例 #17
0
        /// <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();
            }
        }
コード例 #18
0
        /// <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);
        }
コード例 #19
0
        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);
        }
コード例 #20
0
        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() }
            };
        }
コード例 #21
0
        /// <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);
                        }
                    }
                }
            }
        }
コード例 #22
0
        /// <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));
        }
コード例 #23
0
        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));
        }
コード例 #24
0
        /// <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? */);
                }
            }
        }
コード例 #25
0
ファイル: ClientEdmModel.cs プロジェクト: zdzislaw/odata.net
        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);
        }
コード例 #26
0
        /// <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);
            }
        }
コード例 #27
0
        /// <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);
        }
コード例 #28
0
        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);
            }
        }
コード例 #29
0
        /// <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);
        }
コード例 #30
0
        private void ResolveByCreating(MaterializerEntry entry, Type expectedEntryType)
        {
            ClientTypeAnnotation annotation = base.ResponseInfo.TypeResolver.ResolveEdmTypeName(expectedEntryType, entry.Entry.TypeName);

            this.ResolveByCreatingWithType(entry, annotation.ElementType);
        }