private static void VerifyIsVersion4(Type type)
 {
     ClientEdmModel model = new ClientEdmModel(ODataProtocolVersion.V4);
     IEdmType edmType = model.GetOrCreateEdmType(type);
     var typeAnnotation = model.GetClientTypeAnnotation(edmType);
     Assert.AreEqual(typeAnnotation.GetMetadataVersion(), new Version(4, 0), "Type with geography point must have 4.0 version");
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates an instance of TypeResolver class.
        /// </summary>
        /// <param name="model">The client model.</param>
        /// <param name="resolveTypeFromName">The callback to resolve client CLR types.</param>
        /// <param name="resolveNameFromType">The callback for resolving server type names.</param>
        /// <param name="serviceModel">The service model.</param>
        internal TypeResolver(ClientEdmModel model, Func<string, Type> resolveTypeFromName, Func<Type, string> resolveNameFromType, IEdmModel serviceModel)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(resolveTypeFromName != null, "resolveTypeFromName != null");
            Debug.Assert(resolveNameFromType != null, "resolveNameFromType != null");
            this.resolveTypeFromName = resolveTypeFromName;
            this.resolveNameFromType = resolveNameFromType;
            this.serviceModel = serviceModel;
            this.clientEdmModel = model;

            if (serviceModel != null && clientEdmModel != null)
            {
                if (clientEdmModel.EdmStructuredSchemaElements == null)
                {
                    clientEdmModel.EdmStructuredSchemaElements = serviceModel.SchemaElements.Where(se => se is IEdmStructuredType).ToList();
                }
                else
                {
                    foreach (var element in serviceModel.SchemaElements.Where(se => se is IEdmStructuredType))
                    {
                        if (!clientEdmModel.EdmStructuredSchemaElements.Contains(element))
                        {
                            clientEdmModel.EdmStructuredSchemaElements.Add(element);
                        }
                    }
                }
            }
        }
        public void ShortIntegrationTestToValidateEntryShouldBeRead()
        {
            var odataEntry = new ODataEntry() { Id = new Uri("http://services.odata.org/OData/OData.svc/Customers(0)") };
            odataEntry.Properties = new ODataProperty[] { new ODataProperty() { Name = "ID", Value = 0 }, new ODataProperty() { Name = "Description", Value = "Simple Stuff" } };

            var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
            var context = new DataServiceContext();
            MaterializerEntry.CreateEntry(odataEntry, ODataFormat.Atom, true, clientEdmModel);
            var materializerContext = new TestMaterializerContext() {Model = clientEdmModel, Context = context};
            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
            QueryComponents components = new QueryComponents(new Uri("http://foo.com/Service"), new Version(4, 0), typeof(Customer), null, new Dictionary<Expression, Expression>());

            var entriesMaterializer = new ODataEntriesEntityMaterializer(new ODataEntry[] { odataEntry }, materializerContext, adapter, components, typeof(Customer), null, ODataFormat.Atom);
            
            var customersRead = new List<Customer>();

            // This line will call ODataEntityMaterializer.ReadImplementation() which will reconstruct the entity, and will get non-public setter called.
            while (entriesMaterializer.Read())
            {
                customersRead.Add(entriesMaterializer.CurrentValue as Customer);
            }

            customersRead.Should().HaveCount(1);
            customersRead[0].ID.Should().Be(0);
            customersRead[0].Description.Should().Be("Simple Stuff");
        }
        /// <summary>
        /// Instantiates a new Serializer class and calls WriteEntry method on it.
        /// </summary>
        /// <param name="dataServiceContext"></param>
        /// <returns></returns>
        private static Person SetupSerializerAndCallWriteEntry(DataServiceContext dataServiceContext)
        {
            Person person = new Person();
            Address address = new Address();
            Car car1 = new Car();
            person.Cars.Add(car1);
            person.HomeAddress = address;

            dataServiceContext.AttachTo("Cars", car1);
            dataServiceContext.AttachTo("Addresses", address);

            var requestInfo = new RequestInfo(dataServiceContext);
            var serializer = new Serializer(requestInfo);
            var headers = new HeaderCollection();
            var clientModel = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityDescriptor = new EntityDescriptor(clientModel);
            entityDescriptor.State = EntityStates.Added;
            entityDescriptor.Entity = person;
            var requestMessageArgs = new BuildingRequestEventArgs("POST", new Uri("http://www.foo.com/Northwind"), headers, entityDescriptor, HttpStack.Auto);
            var linkDescriptors = new LinkDescriptor[] { new LinkDescriptor(person, "Cars", car1, clientModel), new LinkDescriptor(person, "HomeAddress", address, clientModel) };
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);
            return person;
        }
 public void Initialize()
 {
     this.clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
     this.clientEdmModel.GetOrCreateEdmType(typeof(TestCustomer));
     this.clientEdmModel.GetOrCreateEdmType(typeof(TestOrder));
     this.materializerContext = new TestMaterializerContext() { Model = this.clientEdmModel };
     this.ordersProperty = this.clientEdmModel.GetClientTypeAnnotation(typeof(TestCustomer)).GetProperty("Orders", false);
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="EntityTrackingAdapter" /> class.
 /// </summary>
 /// <param name="entityTracker">The entity tracker.</param>
 /// <param name="mergeOption">The merge option.</param>
 /// <param name="model">The model.</param>
 /// <param name="context">The context.</param>
 internal EntityTrackingAdapter(EntityTrackerBase entityTracker, MergeOption mergeOption, ClientEdmModel model, DataServiceContext context)
 {
     this.MaterializationLog = new AtomMaterializerLog(mergeOption, model, entityTracker);
     this.MergeOption = mergeOption;
     this.EntityTracker = entityTracker;
     this.Model = model;
     this.Context = context;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="FeedAndEntryMaterializerAdapter"/> class. Used for tests so no ODataMessageReader is required
 /// </summary>
 /// <param name="odataFormat">The format of the reader.</param>
 /// <param name="reader">The reader.</param>
 /// <param name="model">The model.</param>
 /// <param name="mergeOption">The mergeOption.</param>
 internal FeedAndEntryMaterializerAdapter(ODataFormat odataFormat, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption)
 {
     this.readODataFormat = odataFormat;
     this.clientEdmModel = model;
     this.mergeOption = mergeOption;
     this.reader = reader;
     this.currentEntry = null;
     this.currentFeed = null;
     this.feedEntries = null;
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Initializes a new <see cref="AtomMaterializerLog"/> instance.
        /// </summary>
        /// <param name="mergeOption">The merge option for the log.</param>
        /// <param name="model">The model for the log.</param>
        /// <param name="entityTracker">The entity tracker for the log.</param>
        /// <remarks>
        /// Note that the merge option can't be changed.
        /// </remarks>
        internal AtomMaterializerLog(MergeOption mergeOption, ClientEdmModel model, EntityTrackerBase entityTracker)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(entityTracker != null, "entityTracker != null");

            this.appendOnlyEntries = new Dictionary<Uri, ODataEntry>(EqualityComparer<Uri>.Default);
            this.mergeOption = mergeOption;
            this.clientEdmModel = model;
            this.entityTracker = entityTracker;
            this.identityStack = new Dictionary<Uri, ODataEntry>(EqualityComparer<Uri>.Default);
            this.links = new List<LinkDescriptor>();
        }
        public void Init()
        {
            this._address = new Address { Street = "123 fake st" };
            this._entity = new Customer { Id = 1, Address = this._address, Emails = new List<string> { "*****@*****.**"} };

            var model = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityType = model.GetOrCreateEdmType(typeof(Customer));
            var complexType = model.GetOrCreateEdmType(typeof(Address));

            this._complexValue = new ClientEdmStructuredValue(this._address, model, model.GetClientTypeAnnotation(complexType));
            this._entityValue = new ClientEdmStructuredValue(this._entity, model, model.GetClientTypeAnnotation(entityType));
        }
        public void ValidateShortIntegrationFeedReading()
        {
            var initialFeed = new ODataFeed() {Id = new Uri("http://services.odata.org/OData/OData.svc/Products")};
            
            var productItem = new ODataEntry() {Id = new Uri("http://services.odata.org/OData/OData.svc/Products(0)")};
            productItem.Properties = new ODataProperty[] {new ODataProperty() {Name = "Id", Value = 0}};

            var categoryNavigationLink = new ODataNavigationLink() {Name = "Category"};

            var categoryItem = new ODataEntry() { Id = new Uri("http://services.odata.org/OData/OData.svc/Categories(0)") };
            categoryItem.Properties = new ODataProperty[] { new ODataProperty() { Name = "Id", Value = 0 } };

            var productsNavigationLink = new ODataNavigationLink() { Name = "Products" };

            var supplierNavigationLink = new ODataNavigationLink() { Name = "Supplier" };

            var testODataReader = new TestODataReader()
            {
               new TestODataReaderItem(ODataReaderState.FeedStart, initialFeed),
               new TestODataReaderItem(ODataReaderState.EntryStart, productItem),
               new TestODataReaderItem(ODataReaderState.NavigationLinkStart, categoryNavigationLink),
               new TestODataReaderItem(ODataReaderState.EntryStart, categoryItem),
               new TestODataReaderItem(ODataReaderState.NavigationLinkStart, productsNavigationLink),
               new TestODataReaderItem(ODataReaderState.NavigationLinkEnd, productsNavigationLink),
               new TestODataReaderItem(ODataReaderState.EntryEnd, categoryItem),
               new TestODataReaderItem(ODataReaderState.NavigationLinkEnd, categoryNavigationLink),
               new TestODataReaderItem(ODataReaderState.NavigationLinkStart, supplierNavigationLink),
               new TestODataReaderItem(ODataReaderState.NavigationLinkEnd, supplierNavigationLink),
               new TestODataReaderItem(ODataReaderState.EntryEnd, productItem),
               new TestODataReaderItem(ODataReaderState.FeedEnd, initialFeed),
            };

            ClientEdmModel clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);

            var responsePipeline = new DataServiceClientResponsePipelineConfiguration(new DataServiceContext());
            var odataReaderWrapper = ODataReaderWrapper.CreateForTest(testODataReader, responsePipeline);
            FeedAndEntryMaterializerAdapter reader = new FeedAndEntryMaterializerAdapter(ODataFormat.Atom, odataReaderWrapper, clientEdmModel, MergeOption.OverwriteChanges);

            int readCounter = 0;

            while (reader.Read())
            {
                readCounter++;
            }

            readCounter.Should().Be(2);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Creates an instance of TypeResolver class.
        /// </summary>
        /// <param name="model">The client model.</param>
        /// <param name="resolveTypeFromName">The callback to resolve client CLR types.</param>
        /// <param name="resolveNameFromType">The callback for resolving server type names.</param>
        /// <param name="serviceModel">The service model.</param>
        internal TypeResolver(ClientEdmModel model, Func <string, Type> resolveTypeFromName, Func <Type, string> resolveNameFromType, IEdmModel serviceModel)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(resolveTypeFromName != null, "resolveTypeFromName != null");
            Debug.Assert(resolveNameFromType != null, "resolveNameFromType != null");
            this.resolveTypeFromName = resolveTypeFromName;
            this.resolveNameFromType = resolveNameFromType;
            this.serviceModel        = serviceModel;
            this.clientEdmModel      = model;

            if (serviceModel != null && clientEdmModel != null)
            {
                foreach (var element in serviceModel.SchemaElements.Where(se => se is IEdmStructuredType))
                {
                    clientEdmModel.EdmStructuredSchemaElements.TryAdd(element.Name, element);
                }
            }
        }
Ejemplo n.º 12
0
        /// <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);
                if (serverTypeName == null)
                {
                    serverTypeName = this.requestInfo.InferServerTypeNameFromServerModel(entityDescriptor);
                }

                IEnumerable <ClientPropertyAnnotation> properties;
                if ((!Util.IsFlagSet(this.options, SaveChangesOptions.ReplaceOnUpdate) &&
                     entityDescriptor.State == EntityStates.Modified &&
                     entityDescriptor.PropertiesToSerialize.Any()) ||
                    (Util.IsFlagSet(this.options, SaveChangesOptions.PostOnlySetProperties) &&
                     entityDescriptor.State == EntityStates.Added))
                {
                    properties = entityType.PropertiesToSerialize().Where(prop => entityDescriptor.PropertiesToSerialize.Contains(prop.PropertyName));
                }
                else
                {
                    properties = entityType.PropertiesToSerialize();
                }

                entry.Properties = this.propertyConverter.PopulateProperties(entityDescriptor.Entity, serverTypeName, properties);

                entryWriter.WriteStart(entry, entityDescriptor.Entity);

                if (EntityStates.Added == entityDescriptor.State)
                {
                    this.WriteNavigationLink(entityDescriptor, relatedLinks, entryWriter);
                }

                entryWriter.WriteEnd(entry, entityDescriptor.Entity);
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Get or create a client EDM type instance.
        /// </summary>
        /// <param name="type">type to wrap</param>
        /// <returns>client type</returns>
        internal IEdmType GetOrCreateEdmType(Type type)
        {
            Debug.Assert(type != null, "type != null");

            EdmTypeCacheValue cachedEdmType;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType);
            }

            if (cachedEdmType == null)
            {
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    cachedEdmType = this.GetOrCreateEdmTypeInternal(null /*baseType*/, type, ClientTypeUtil.EmptyPropertyInfoArray, false /*isEntity*/, false /*hasProperties*/);
                }
                else
                {
                    PropertyInfo[] keyProperties;
                    bool           hasProperties;
                    Type[]         hierarchy = ClientEdmModel.GetTypeHierarchy(type, out keyProperties, out hasProperties);

                    Debug.Assert(keyProperties == null || keyProperties.Length == 0 || keyProperties.All(p => p.DeclaringType == keyProperties[0].DeclaringType), "All key properties must be declared on the same type.");

                    bool isEntity = keyProperties != null;
                    keyProperties = keyProperties ?? ClientTypeUtil.EmptyPropertyInfoArray;
                    foreach (Type t in hierarchy)
                    {
                        // Pass in the full list of key properties for the most base type to be added there.  We only allow key properties to be
                        // declared on the same type.
                        IEdmStructuredType edmBaseType = cachedEdmType == null ? null : cachedEdmType.EdmType as IEdmStructuredType;
                        cachedEdmType = this.GetOrCreateEdmTypeInternal(edmBaseType, t, keyProperties, isEntity, t == type ? hasProperties : (bool?)null);

                        // Pass in an empty PropertyInfo array on subsequent derived types.
                        keyProperties = ClientTypeUtil.EmptyPropertyInfoArray;
                    }
                }
            }

            Debug.Assert(cachedEdmType != null, "cachedEdmType != null");
            this.ValidateComplexTypeHasProperties(type, cachedEdmType);
            return(cachedEdmType.EdmType);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Checks if the provided type is a collection type (i.e. it implements ICollection and the collection item type is not an entity).
        /// </summary>
        /// <param name="type">Type being checked.</param>
        /// <param name="model">The client model.</param>
        /// <returns>True if the CLR type is a collection compatible type. False otherwise.</returns>
        internal static bool IsCLRTypeCollection(Type type, ClientEdmModel model)
        {
            // char[] and byte[] implements ICollection<> but we should not threat them as collections since they are primitive types for us.
            if (!PrimitiveType.IsKnownNullableType(type))
            {
                Type collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>));
                if (collectionType != null)
                {
                    // collectionType is ICollection so we know that the first generic parameter
                    // is the collection item type
                    if (!ClientTypeUtil.TypeIsEntity(collectionType.GetGenericArguments()[0], model))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 15
0
        public void Init()
        {
            this.clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
            this.entityDescriptor = new EntityDescriptor(this.clientEdmModel) { Entity = new Customer() };

            var serverType = new EdmEntityType("FQ.NS", "MyServerType");
            serverType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "Navigation", Target = serverType, TargetMultiplicity = EdmMultiplicity.ZeroOrOne });
            this.serverTypeName = ((IEdmSchemaElement)serverType).FullName();
            var serverContainer = new EdmEntityContainer("FQ.NS", "MyContainer");
            this.serverEntitySet = serverContainer.AddEntitySet("MyEntitySet", serverType);

            var serverModel = new EdmModel();
            serverModel.AddElement(serverType);
            serverModel.AddElement(serverContainer);

            this.ctx = new DataServiceContext(new Uri("http://temp.org/"), ODataProtocolVersion.V4, this.clientEdmModel);
            this.ctx.Format.UseJson(serverModel);
            this.testSubject = new RequestInfo(ctx);
        }
        /// <summary>
        /// Validates the specified <paramref name="property"/> matches 
        /// the parsed <paramref name="link"/>.
        /// </summary>
        /// <param name="property">Property as understood by the type system.</param>
        /// <param name="link">Property as parsed.</param>
        /// <param name="model">Client Model.</param>
        /// <param name="performEntityCheck">whether to do the entity check or not.</param>
        /// <returns>The type</returns>
        internal static Type ValidatePropertyMatch(ClientPropertyAnnotation property, ODataNavigationLink link, ClientEdmModel model, bool performEntityCheck)
        {
            Debug.Assert(property != null, "property != null");
            Debug.Assert(link != null, "link != null");

            Type propertyType = null;
            if (link.IsCollection.HasValue)
            {
                if (link.IsCollection.Value)
                {
                    // We need to fail if the payload states that the property is a navigation collection property
                    // and in the client, the property is not a collection property.
                    if (!property.IsEntityCollection)
                    {
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName));
                    }

                    propertyType = property.EntityCollectionItemType;
                }
                else
                {
                    if (property.IsEntityCollection)
                    {
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName));
                    }

                    propertyType = property.PropertyType;
                }
            }

            // If the server type and the client type does not match, we need to throw.
            // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa
            if (propertyType != null && performEntityCheck)
            {
                if (!ClientTypeUtil.TypeIsEntity(propertyType, model))
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString()));
                }
            }

            return propertyType;
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Converts CLR value into ODataEnumValue.
        /// </summary>
        /// <param name="enumClrType">The CLR type.</param>
        /// <param name="value">The Enum value.</param>
        /// <param name="isCollectionItem">The bool isCollectionItem.</param>
        /// <returns>An ODataEnumValue instance.</returns>
        internal ODataEnumValue CreateODataEnumValue(Type enumClrType, object value, bool isCollectionItem)
        {
            Debug.Assert(enumClrType != null && enumClrType.IsEnum(), "enumClrType != null && enumClrType.IsEnum");
            Debug.Assert(value != null || !isCollectionItem, "Collection items must not be null");

            ClientEdmModel       model = this.requestInfo.Model;
            ClientTypeAnnotation enumTypeAnnotation = model.GetClientTypeAnnotation(enumClrType);

            Debug.Assert(enumTypeAnnotation != null, "enumTypeAnnotation != null");
            Debug.Assert(!enumTypeAnnotation.IsEntityType, "Unexpected entity");

            // Handle null value by putting m:null="true"
            if (value == null)
            {
                Debug.Assert(!isCollectionItem, "Null collection items are not supported. Should have already been checked.");
                return(null);
            }

            return(new ODataEnumValue(ClientTypeUtil.GetEnumValuesString(value.ToString(), enumClrType), enumTypeAnnotation.ElementTypeName));
        }
Ejemplo n.º 18
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;
        }
Ejemplo n.º 19
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;
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Get the entity set name for the target entity object.
        /// </summary>
        /// <param name="target">An entity object.</param>
        /// <param name="targetEntitySet">The 'currently known' entity set name for the target object.</param>
        /// <param name="model">The client model.</param>
        /// <returns>The entity set name for the target object.</returns>
        /// <remarks>
        /// Allow user code to provide the entity set name. If user code does not provide the entity set name, then
        /// this method will get the entity set name from the value of the EntitySetAttribute.
        /// The 'currently known' entity set name for top level collections can be provided through OEC constructor
        /// </remarks>
        internal static string GetEntitySet(
            object target,
            string targetEntitySet,
            ClientEdmModel model)
        {
            Debug.Assert(target != null, "Argument 'target' cannot be null.");
            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType(), model), "Argument 'target' must be an entity type.");

            // Here's the rules in order of priority for resolving entity set name
            // 1. EntitySet name passed in the constructor or extension methods of DataServiceCollection
            // 2. EntitySet name specified in the EntitySet attribute by the code gen. {Remember this attribute is
            //    not generated in case of MEST)
            if (!String.IsNullOrEmpty(targetEntitySet))
            {
                return(targetEntitySet);
            }
            else
            {
                // If there is not a 'currently known' entity set name to validate against, then there must be
                // EntitySet attribute on the entity type
                return(BindingEntityInfo.GetEntitySetAttribute(target.GetType(), model));
            }
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Creates a new instance of MaterializerEntry.
        /// </summary>
        /// <param name="entry">The entry.</param>
        /// <param name="format">The format the entry was read in.</param>
        /// <param name="isTracking">True if the contents of the entry will be tracked in the context, otherwise False.</param>
        /// <param name="model">The client model.</param>
        private MaterializerEntry(ODataEntry entry, ODataFormat format, bool isTracking, ClientEdmModel model)
        {
            Debug.Assert(entry != null, "entry != null");

            this.entry = entry;
            this.Format = format;
            this.entityDescriptor = new EntityDescriptor(model);
#pragma warning disable 618
            this.isAtomOrTracking = isTracking || this.Format == ODataFormat.Atom;
#pragma warning restore 618
            string serverTypeName = this.Entry.TypeName;
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation<SerializationTypeNameAnnotation>();
            if (serializationTypeNameAnnotation != null)
            {
                // If the annotation has a value use it. Otherwise, in JSON-Light, the types can be inferred from the
                // context URI even if they are not present on the wire, so just use the type name from the entry.
                if (serializationTypeNameAnnotation.TypeName != null || this.Format != ODataFormat.Json)
                {
                    serverTypeName = serializationTypeNameAnnotation.TypeName;
                }
            }

            this.entityDescriptor.ServerTypeName = serverTypeName;
        }
Ejemplo n.º 22
0
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="edmProperty">Back reference to the EdmProperty this annotation is part of.</param>
        /// <param name="propertyInfo">propertyInfo instance.</param>
        /// <param name="model">The client model.</param>
        internal ClientPropertyAnnotation(IEdmProperty edmProperty, PropertyInfo propertyInfo, ClientEdmModel model)
        {
            Debug.Assert(edmProperty != null, "edmProperty != null");
            Debug.Assert(propertyInfo != null, "null propertyInfo");

            // Property should always have DeclaringType
            Debug.Assert(propertyInfo.DeclaringType != null, "Property without a declaring type");

            this.EdmProperty = edmProperty;
            this.PropertyName = ClientTypeUtil.GetServerDefinedName(propertyInfo);
            this.PropertyInfo = propertyInfo;
            this.NullablePropertyType = propertyInfo.PropertyType;
            this.PropertyType = Nullable.GetUnderlyingType(this.NullablePropertyType) ?? this.NullablePropertyType;
            this.DeclaringClrType = propertyInfo.DeclaringType;

            MethodInfo propertyGetMethod = propertyInfo.GetGetMethod();

            // Add the parameter to make set method is returned even it is not public. Portable lib does not support this.
#if PORTABLELIB
            MethodInfo propertySetMethod = propertyInfo.GetSetMethod();
#else
            MethodInfo propertySetMethod = propertyInfo.GetSetMethod(true);
#endif

            ParameterExpression instance = Expression.Parameter(typeof(Object), "instance");
            ParameterExpression value = Expression.Parameter(typeof(Object), "value");

            // instance => (Object)(((T)instance).get_PropertyName());  <-- we need to box the value back to object to return
            this.propertyGetter = propertyGetMethod == null ? null : (Func<object, object>)Expression.Lambda(
                Expression.Convert(
                    Expression.Call(
                        Expression.Convert(instance, this.DeclaringClrType),
                        propertyGetMethod),
                    typeof(Object)),
                instance).Compile();

            // (instance, value) => ((T)instance).set_PropertyName((T1)value);
            this.propertySetter = propertySetMethod == null ? null : (Action<object, object>)Expression.Lambda(
                Expression.Call(
                    Expression.Convert(instance, this.DeclaringClrType),
                    propertySetMethod,
                    Expression.Convert(value, this.NullablePropertyType)),
                instance,
                value).Compile();

            this.Model = model;

            this.IsKnownType = PrimitiveType.IsKnownType(this.PropertyType);

            // non primitive types: dictionary/collections
            if (!this.IsKnownType)
            {
                var setMethodInfo = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(IDictionary<,>), "set_Item", out this.DictionaryValueType);

                if (setMethodInfo != null)
                {
                    ParameterExpression propertyNameParam = Expression.Parameter(typeof(String), "propertyName");

                    // (instance, propertyName, value) => ((IDictionary<string, DictionaryValueType>)instance)[propertyName] = (DictionaryValueType)value;
                    this.dictionarySetter = (Action<Object, String, Object>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, typeof(IDictionary<,>).MakeGenericType(typeof(String), this.DictionaryValueType)),
                            setMethodInfo,
                            propertyNameParam,
                            Expression.Convert(value, this.DictionaryValueType)),
                        instance,
                        propertyNameParam,
                        value).Compile();
                }
                else
                {
                    var containsMethod = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection<>), "Contains", out this.collectionGenericType);
                    var addMethod = ClientTypeUtil.GetAddToCollectionMethod(this.PropertyType, out this.collectionGenericType);
                    var removeMethod = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection<>), "Remove", out this.collectionGenericType);
                    var clearMethod = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection<>), "Clear", out this.collectionGenericType);

                    // (instance, value) => ((PropertyType)instance).Contains((CollectionType)value);  returns boolean
                    this.collectionContains = containsMethod == null ? null : (Func<Object, Object, Boolean>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            containsMethod,
                            Expression.Convert(value, this.collectionGenericType)),
                        instance,
                        value).Compile();

                    // (instance, value) => ((PropertyType)instance).Add((CollectionType)value);
                    this.collectionAdd = addMethod == null ? null : (Action<Object, Object>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            addMethod,
                            Expression.Convert(value, this.collectionGenericType)),
                        instance,
                        value).Compile();

                    // (instance, value) => ((PropertyType)instance).Remove((CollectionType)value);  returns boolean
                    this.collectionRemove = removeMethod == null ? null : (Func<Object, Object, Boolean>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            removeMethod,
                            Expression.Convert(value, this.collectionGenericType)),
                        instance,
                        value).Compile();

                    // (instance) => ((PropertyType)instance).Clear();
                    this.collectionClear = clearMethod == null ? null : (Action<Object>)Expression.Lambda(
                        Expression.Call(
                             Expression.Convert(instance, this.PropertyType),
                             clearMethod),
                        instance).Compile();
                }
            }

            Debug.Assert(this.collectionGenericType == null || this.DictionaryValueType == null, "collectionGenericType and DictionaryItemType mutually exclusive. (They both can be null though).");
        }
Ejemplo n.º 23
0
 /// <summary>Obtain binding info corresponding to a given type</summary>
 /// <param name="entityType">Type for which to obtain information</param>
 /// <param name="model">the client model.</param>
 /// <returns>Info about the <paramref name="entityType"/></returns>
 internal static IList <BindingPropertyInfo> GetObservableProperties(Type entityType, ClientEdmModel model)
 {
     return(GetBindingEntityInfoFor(entityType, model).ObservableProperties);
 }
Ejemplo n.º 24
0
        /// <summary>
        /// Writes the body operation parameters associated with a ServiceAction. For each BodyOperationParameter:
        /// 1. calls ODataPropertyConverter  to convert CLR object into ODataValue/primitive values.
        /// 2. then calls ODataParameterWriter to write the ODataValue/primitive values.
        /// </summary>
        /// <param name="operationParameters">The list of operation parameters to write.</param>
        /// <param name="requestMessage">The OData request message used to write the operation parameters.</param>
        internal void WriteBodyOperationParameters(List <BodyOperationParameter> operationParameters, ODataRequestMessageWrapper requestMessage)
        {
            Debug.Assert(requestMessage != null, "requestMessage != null");
            Debug.Assert(operationParameters != null, "operationParameters != null");
            Debug.Assert(operationParameters.Any(), "operationParameters.Any()");

            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, true /*isParameterPayload*/))
            {
                ODataParameterWriter parameterWriter = messageWriter.CreateODataParameterWriter((IEdmOperation)null);
                parameterWriter.WriteStart();

                foreach (OperationParameter operationParameter in operationParameters)
                {
                    if (operationParameter.Value == null)
                    {
                        parameterWriter.WriteValue(operationParameter.Name, operationParameter.Value);
                    }
                    else
                    {
                        ClientEdmModel model   = this.requestInfo.Model;
                        IEdmType       edmType = model.GetOrCreateEdmType(operationParameter.Value.GetType());
                        Debug.Assert(edmType != null, "edmType != null");

                        switch (edmType.TypeKind)
                        {
                        case EdmTypeKind.Collection:
                        {
                            // TODO: just call ODataPropertyConverter.CreateODataCollection()
                            IEnumerator           enumerator           = ((ICollection)operationParameter.Value).GetEnumerator();
                            ODataCollectionWriter collectionWriter     = parameterWriter.CreateCollectionWriter(operationParameter.Name);
                            ODataCollectionStart  odataCollectionStart = new ODataCollectionStart();
                            collectionWriter.WriteStart(odataCollectionStart);

                            while (enumerator.MoveNext())
                            {
                                Object collectionItem = enumerator.Current;
                                if (collectionItem == null)
                                {
                                    throw new NotSupportedException(Strings.Serializer_NullCollectionParamterItemValue(operationParameter.Name));
                                }

                                IEdmType edmItemType = model.GetOrCreateEdmType(collectionItem.GetType());
                                Debug.Assert(edmItemType != null, "edmItemType != null");

                                switch (edmItemType.TypeKind)
                                {
                                case EdmTypeKind.Complex:
                                {
                                    Debug.Assert(model.GetClientTypeAnnotation(edmItemType).ElementType != null, "edmItemType.GetClientTypeAnnotation().ElementType != null");
                                    ODataComplexValue complexValue = this.propertyConverter.CreateODataComplexValue(
                                        model.GetClientTypeAnnotation(edmItemType).ElementType,
                                        collectionItem,
                                        null /*propertyName*/,
                                        false /*isCollectionItem*/,
                                        null /*visitedComplexTypeObjects*/);

                                    Debug.Assert(complexValue != null, "complexValue != null");
                                    collectionWriter.WriteItem(complexValue);
                                    break;
                                }

                                case EdmTypeKind.Primitive:
                                {
                                    object primitiveItemValue = ODataPropertyConverter.ConvertPrimitiveValueToRecognizedODataType(collectionItem, collectionItem.GetType());
                                    collectionWriter.WriteItem(primitiveItemValue);
                                    break;
                                }

                                case EdmTypeKind.Enum:
                                {
                                    ODataEnumValue enumTmp = this.propertyConverter.CreateODataEnumValue(
                                        model.GetClientTypeAnnotation(edmItemType).ElementType,
                                        collectionItem,
                                        false);
                                    collectionWriter.WriteItem(enumTmp);
                                    break;
                                }

                                default:

                                    // EdmTypeKind.Entity
                                    // EdmTypeKind.Row
                                    // EdmTypeKind.EntityReference
                                    throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(operationParameter.Name, edmItemType.TypeKind));
                                }
                            }

                            collectionWriter.WriteEnd();
                            collectionWriter.Flush();
                            break;
                        }

                        case EdmTypeKind.Complex:
                        {
                            Debug.Assert(model.GetClientTypeAnnotation(edmType).ElementType != null, "model.GetClientTypeAnnotation(edmType).ElementType != null");
                            ODataComplexValue complexValue = this.propertyConverter.CreateODataComplexValue(
                                model.GetClientTypeAnnotation(edmType).ElementType,
                                operationParameter.Value,
                                null /*propertyName*/,
                                false /*isCollectionItemType*/,
                                null /*visitedComplexTypeObjects*/);

                            Debug.Assert(complexValue != null, "complexValue != null");
                            parameterWriter.WriteValue(operationParameter.Name, complexValue);
                            break;
                        }

                        case EdmTypeKind.Primitive:
                            object primitiveValue = ODataPropertyConverter.ConvertPrimitiveValueToRecognizedODataType(operationParameter.Value, operationParameter.Value.GetType());
                            parameterWriter.WriteValue(operationParameter.Name, primitiveValue);
                            break;

                        case EdmTypeKind.Enum:
                            ODataEnumValue tmp = this.propertyConverter.CreateODataEnumValue(
                                model.GetClientTypeAnnotation(edmType).ElementType,
                                operationParameter.Value,
                                false);
                            parameterWriter.WriteValue(operationParameter.Name, tmp);

                            break;

                        default:
                            // EdmTypeKind.Entity
                            // EdmTypeKind.Row
                            // EdmTypeKind.EntityReference
                            throw new NotSupportedException(Strings.Serializer_InvalidParameterType(operationParameter.Name, edmType.TypeKind));
                        }
                    } // else
                }     // foreach

                parameterWriter.WriteEnd();
                parameterWriter.Flush();
            }
        }
Ejemplo n.º 25
0
        /// <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);
        }
Ejemplo n.º 26
0
        /// <summary>Obtain binding info corresponding to a given type</summary>
        /// <param name="entityType">Type for which to obtain information</param>
        /// <param name="model">The client model.</param>
        /// <returns>Info about the <paramref name="entityType"/></returns>
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType, ClientEdmModel model)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also.
            // EntitySetAttribute does not allow multiples, so there can be at most 1 instance on the type.
            EntitySetAttribute entitySetAttribute = (EntitySetAttribute)entityType.GetCustomAttributes(typeof(EntitySetAttribute), true).SingleOrDefault();

            // There must be exactly one (unambiguous) EntitySetAttribute attribute.
            bindingEntityInfo.EntitySet  = entitySetAttribute != null ? entitySetAttribute.EntitySet : null;
            bindingEntityInfo.ClientType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityType));

            foreach (ClientPropertyAnnotation p in bindingEntityInfo.ClientType.Properties())
            {
                BindingPropertyInfo bpi = null;
                Type propertyType       = p.PropertyType;

                if (p.IsStreamLinkProperty)
                {
                    // DataServiceStreamLink is not mutable externally
                    // It implements INPC to notify controls about our updates
                    // We should ignore its events since we are the only one updating it.
                    continue;
                }
                else if (p.IsPrimitiveOrEnumOrComplexCollection)
                {
                    Debug.Assert(!BindingEntityInfo.IsDataServiceCollection(propertyType, model), "DataServiceCollection cannot be the type that backs collections of primitives or complex types.");
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection
                    };
                }
                else if (p.IsEntityCollection)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType, model))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindDataServiceCollection
                        };
                    }
                }
                else if (BindingEntityInfo.IsEntityType(propertyType, model))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else if (BindingEntityInfo.CanBeComplexType(propertyType))
                {
                    // Add complex types and nothing else.
                    Debug.Assert(!p.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    // For entity types, all of the above types of properties are interesting.
                    // For complex types, only observe collections and complex type properties.
                    if (bindingEntityInfo.ClientType.IsEntityType ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="FeedAndEntryMaterializerAdapter"/> class.
 /// </summary>
 /// <param name="messageReader">The messageReader that is used to get the format of the reader.</param>
 /// <param name="reader">The reader.</param>
 /// <param name="model">The model.</param>
 /// <param name="mergeOption">The mergeOption.</param>
 internal FeedAndEntryMaterializerAdapter(ODataMessageReader messageReader, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption)
     : this(ODataUtils.GetReadFormat(messageReader), reader, model, mergeOption)
 {
 }
Ejemplo n.º 28
0
 /// <summary>Verifies the absence of observer for an DataServiceCollection</summary>
 /// <typeparam name="T">Type of DataServiceCollection</typeparam>
 /// <param name="oec">Non-typed collection object</param>
 /// <param name="sourceProperty">Collection property of the source object which is being assigned to</param>
 /// <param name="sourceType">Type of the source object</param>
 /// <param name="model">The client model.</param>
 internal static void VerifyObserverNotPresent <T>(object oec, string sourceProperty, Type sourceType, ClientEdmModel model)
 public TestClientContext(Uri serviceRoot, ODataProtocolVersion version, ClientEdmModel model)
     : base(serviceRoot, version, model)
 {
 }
        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 EdmIntegerConstant(1)));
            colorType.AddMember(new EdmEnumMember(colorType, "Blue", new EdmIntegerConstant(2)));
            colorType.AddMember(new EdmEnumMember(colorType, "Green", new EdmIntegerConstant(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() }
            };
        }
Ejemplo n.º 31
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="source">Source entity</param>
 /// <param name="sourceProperty">Navigation property on the source entity</param>
 /// <param name="target">Target entity</param>
 /// <param name="model">The client model.</param>
 internal LinkDescriptor(object source, string sourceProperty, object target, ClientEdmModel model)
     : this(source, sourceProperty, target, EntityStates.Unchanged)
 {
     this.IsSourcePropertyCollection = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(source.GetType())).GetProperty(sourceProperty, false).IsEntityCollection;
 }
Ejemplo n.º 32
0
 public void Init()
 {
     var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
     this.typeWithUnserializableProperties = new ClientTypeAnnotation(new EdmEntityType("NS", "Type1"), typeof(EntityWithUnserializableProperties), "NS.Type1", clientEdmModel);
     this.typeWithPropertiesInStrangeOrder = new ClientTypeAnnotation(new EdmEntityType("NS", "Type2"), typeof(EntityWithPropertiesInStrangeOrder), "NS.Type2", clientEdmModel);
 }
Ejemplo n.º 33
0
        /// <summary>
        /// Checks whether the specified expression is allowed in a MethodCall. Expressions that
        /// produce collections are not allowed. The only exception is when collection property 
        /// belongs to an entity e.g. c.Orders.Select(o => o), where we allow c.Orders.
        /// </summary>
        /// <param name="e">Expression to check.</param>
        /// <param name="model">The client model used.</param>
        /// <returns>true if expression is disallowed, false otherwise.</returns>
        internal static bool IsDisallowedExpressionForMethodCall(Expression e, ClientEdmModel model)
        {
            // If this is a collection attached to an Entity, then that is fine.
            MemberExpression me = e as MemberExpression;
            if (me != null && ClientTypeUtil.TypeIsEntity(me.Expression.Type, model))
            {
                return false;
            }

            // All collection producing expressions are disallowed.
            return IsCollectionProducingExpression(e);
        }
Ejemplo n.º 34
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);
        }
Ejemplo n.º 35
0
        /// <summary>
        /// Writes collection value in body operation parameter.
        /// </summary>
        /// <param name="parameterWriter">The odata parameter writer.</param>
        /// <param name="operationParameter">The operation parameter.</param>
        /// <param name="edmCollectionType">The edm collection type.</param>
        private void WriteCollectionValueInBodyOperationParameter(ODataParameterWriter parameterWriter, BodyOperationParameter operationParameter, IEdmCollectionType edmCollectionType)
        {
            ClientEdmModel model = this.requestInfo.Model;

            var elementTypeKind = edmCollectionType.ElementType.TypeKind();

            if (elementTypeKind == EdmTypeKind.Entity || elementTypeKind == EdmTypeKind.Complex)
            {
                ODataWriter feedWriter = parameterWriter.CreateResourceSetWriter(operationParameter.Name);
                feedWriter.WriteStart(new ODataResourceSet());

                IEnumerator enumerator = ((ICollection)operationParameter.Value).GetEnumerator();

                while (enumerator.MoveNext())
                {
                    Object collectionItem = enumerator.Current;
                    if (collectionItem == null)
                    {
                        if (elementTypeKind == EdmTypeKind.Complex)
                        {
                            feedWriter.WriteStart((ODataResource)null);
                            feedWriter.WriteEnd();
                            continue;
                        }
                        else
                        {
                            throw new NotSupportedException(Strings.Serializer_NullCollectionParamterItemValue(operationParameter.Name));
                        }
                    }

                    IEdmType edmItemType = model.GetOrCreateEdmType(collectionItem.GetType());
                    Debug.Assert(edmItemType != null, "edmItemType != null");

                    if (edmItemType.TypeKind != EdmTypeKind.Entity && edmItemType.TypeKind != EdmTypeKind.Complex)
                    {
                        throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(operationParameter.Name, edmItemType.TypeKind));
                    }

                    Debug.Assert(model.GetClientTypeAnnotation(edmItemType).ElementType != null, "edmItemType.GetClientTypeAnnotation().ElementType != null");
                    ODataResourceWrapper entry = this.CreateODataResourceFromEntityOperationParameter(model.GetClientTypeAnnotation(edmItemType), collectionItem);
                    Debug.Assert(entry != null, "entry != null");
                    ODataWriterHelper.WriteResource(feedWriter, entry);
                }

                feedWriter.WriteEnd();
                feedWriter.Flush();
            }
            else
            {
                ODataCollectionWriter collectionWriter     = parameterWriter.CreateCollectionWriter(operationParameter.Name);
                ODataCollectionStart  odataCollectionStart = new ODataCollectionStart();
                collectionWriter.WriteStart(odataCollectionStart);

                IEnumerator enumerator = ((ICollection)operationParameter.Value).GetEnumerator();

                while (enumerator.MoveNext())
                {
                    Object collectionItem = enumerator.Current;
                    if (collectionItem == null)
                    {
                        collectionWriter.WriteItem(null);
                        continue;
                    }

                    IEdmType edmItemType = model.GetOrCreateEdmType(collectionItem.GetType());
                    Debug.Assert(edmItemType != null, "edmItemType != null");

                    switch (edmItemType.TypeKind)
                    {
                    case EdmTypeKind.Primitive:
                    {
                        object primitiveItemValue = ODataPropertyConverter.ConvertPrimitiveValueToRecognizedODataType(collectionItem, collectionItem.GetType());
                        collectionWriter.WriteItem(primitiveItemValue);
                        break;
                    }

                    case EdmTypeKind.Enum:
                    {
                        ODataEnumValue enumTmp = this.propertyConverter.CreateODataEnumValue(model.GetClientTypeAnnotation(edmItemType).ElementType, collectionItem, false);
                        collectionWriter.WriteItem(enumTmp);
                        break;
                    }

                    default:
                        // EdmTypeKind.Entity
                        // EdmTypeKind.Row
                        // EdmTypeKind.EntityReference
                        throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(operationParameter.Name, edmItemType.TypeKind));
                    }
                }

                collectionWriter.WriteEnd();
                collectionWriter.Flush();
            }
        }
Ejemplo n.º 36
0
 /// <summary>
 /// gets the UriTranslateResult for a the query
 /// </summary>
 /// <param name="model">The client model.</param>
 /// <returns>an instance of QueryComponents.</returns>
 internal override QueryComponents QueryComponents(ClientEdmModel model)
 {
     return(this.Translate());
 }
Ejemplo n.º 37
0
        /// <summary>
        /// Check to see if the resource to be inserted is a media descriptor, and if so
        /// setup a POST request for the media content first and turn the rest of
        /// the operation into a PUT to update the rest of the properties.
        /// </summary>
        /// <param name="entityDescriptor">The resource to check/process</param>
        /// <returns>An instance of ODataRequestMessage to do POST to the media resource</returns>
        private ODataRequestMessageWrapper CheckAndProcessMediaEntryPost(EntityDescriptor entityDescriptor)
        {
            // TODO: Revisit the design of how media link entries are handled during update
            ClientEdmModel       model = this.RequestInfo.Model;
            ClientTypeAnnotation type  = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType()));

            if (!type.IsMediaLinkEntry && !entityDescriptor.IsMediaLinkEntry)
            {
                // this is not a media link descriptor, process normally
                return(null);
            }

            if (type.MediaDataMember == null && entityDescriptor.SaveStream == null)
            {
                // The entity is marked as MLE but we don't have the content property
                //   and the user didn't set the save stream.
                throw Error.InvalidOperation(Strings.Context_MLEWithoutSaveStream(type.ElementTypeName));
            }

            Debug.Assert(
                (type.MediaDataMember != null && entityDescriptor.SaveStream == null) ||
                (type.MediaDataMember == null && entityDescriptor.SaveStream != null),
                "Only one way of specifying the MR content is allowed.");

            ODataRequestMessageWrapper mediaRequest = null;

            if (type.MediaDataMember != null)
            {
                string contentType   = null;
                int    contentLength = 0;

                if (type.MediaDataMember.MimeTypeProperty == null)
                {
                    contentType = XmlConstants.MimeApplicationOctetStream;
                }
                else
                {
                    object mimeTypeValue = type.MediaDataMember.MimeTypeProperty.GetValue(entityDescriptor.Entity);
                    String mimeType      = mimeTypeValue != null?mimeTypeValue.ToString() : null;

                    if (String.IsNullOrEmpty(mimeType))
                    {
                        throw Error.InvalidOperation(
                                  Strings.Context_NoContentTypeForMediaLink(
                                      type.ElementTypeName,
                                      type.MediaDataMember.MimeTypeProperty.PropertyName));
                    }

                    contentType = mimeType;
                }

                object value = type.MediaDataMember.GetValue(entityDescriptor.Entity);
                if (value == null)
                {
                    this.mediaResourceRequestStream = null;
                }
                else
                {
                    byte[] buffer = value as byte[];
                    if (buffer == null)
                    {
                        string   mime;
                        Encoding encoding;
                        ContentTypeUtil.ReadContentType(contentType, out mime, out encoding);

                        if (encoding == null)
                        {
                            encoding     = Encoding.UTF8;
                            contentType += XmlConstants.MimeTypeUtf8Encoding;
                        }

                        buffer = encoding.GetBytes(ClientConvert.ToString(value));
                    }

                    contentLength = buffer.Length;

                    // Need to specify that the buffer is publicly visible as we need to access it later on
                    this.mediaResourceRequestStream = new MemoryStream(buffer, 0, buffer.Length, false, true);
                }

                HeaderCollection headers = new HeaderCollection();
                headers.SetHeader(XmlConstants.HttpContentLength, contentLength.ToString(CultureInfo.InvariantCulture));
                headers.SetHeader(XmlConstants.HttpContentType, contentType);

                mediaRequest = this.CreateMediaResourceRequest(
                    entityDescriptor.GetResourceUri(this.RequestInfo.BaseUriResolver, false /*queryLink*/),
                    XmlConstants.HttpMethodPost,
                    Util.ODataVersion4,
                    type.MediaDataMember == null, // sendChunked
                    true,                         // applyResponsePreference
                    headers,
                    entityDescriptor);
            }
            else
            {
                HeaderCollection headers = new HeaderCollection();
                this.SetupMediaResourceRequest(headers, entityDescriptor.SaveStream, null /*etag*/);

                mediaRequest = this.CreateMediaResourceRequest(
                    entityDescriptor.GetResourceUri(this.RequestInfo.BaseUriResolver, false /*queryLink*/),
                    XmlConstants.HttpMethodPost,
                    Util.ODataVersion4,
                    type.MediaDataMember == null, // sendChunked
                    true,                         // applyResponsePreference
                    headers,
                    entityDescriptor);
            }

            // Convert the insert into an update for the media link descriptor we just created
            // (note that the identity still needs to be fixed up on the resbox once
            // the response comes with the 'location' header; that happens during processing
            // of the response in SavedResource())
            entityDescriptor.State = EntityStates.Modified;

            return(mediaRequest);
        }
Ejemplo n.º 38
0
        /// <summary>
        /// Gets the type that of the instances that will be returned by materializer.
        /// </summary>
        /// <param name="expectingPrimitiveValue">Whether the expected is a primitive type.</param>
        /// <param name="elementType">Actual type on the client.</param>
        /// <param name="model">The client model used.</param>
        /// <param name="implementationType">The actual type that implements ICollection&lt;&gt;</param>
        /// <returns>Type of the instances that will be returned by materializer.</returns>
        /// <remarks>
        /// For collection navigation properties (i.e. ICollection&lt;T&gt; where T is an entity the method returns T. Materializer will
        /// return single entity each time MoveNext() is called. However for collection properties we need the whole property instead of just a
        /// single collection item.
        /// </remarks>
        private static Type GetTypeForMaterializer(bool expectingPrimitiveValue, Type elementType, ClientEdmModel model, out Type implementationType)
        {
            if (!expectingPrimitiveValue && typeof(IEnumerable).IsAssignableFrom(elementType))
            {
                implementationType = ClientTypeUtil.GetImplementationType(elementType, typeof(ICollection <>));
                if (implementationType != null)
                {
                    Type expectedType = implementationType.GetGenericArguments()[0]; // already know its ICollection<>

                    // We should use the inner type only if this is a collection of entities (as opposed to a collection of primitive or complex types)
                    if (ClientTypeUtil.TypeIsStructured(expectedType, model))
                    {
                        return(expectedType);
                    }
                }
            }

            implementationType = null;
            return(elementType);
        }
Ejemplo n.º 39
0
        /// <summary>
        /// Determine if the specified type is an DataServiceCollection.
        /// </summary>
        /// <remarks>
        /// If there a generic class in the inheritance hierarchy of the type, that has a single
        /// entity type paramenter T, and is assignable to DataServiceCollection(Of T), then
        /// the type is an DataServiceCollection.
        /// </remarks>
        /// <param name="collectionType">An object type specifier.</param>
        /// <param name="model">The client model.</param>
        /// <returns>true if the type is an DataServiceCollection; otherwise false.</returns>
        internal static bool IsDataServiceCollection(Type collectionType, ClientEdmModel model)
        {
            Debug.Assert(collectionType != null, "Argument 'collectionType' cannot be null.");

            metadataCacheLock.EnterReadLock();
            try
            {
                object resultAsObject;
                if (knownObservableCollectionTypes.TryGetValue(collectionType, out resultAsObject))
                {
                    return resultAsObject == TrueObject;
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            Type type = collectionType;
            bool result = false;

            while (type != null)
            {
                if (type.IsGenericType())
                {
                    // Is there a generic class in the inheritance hierarchy, that has a single
                    // entity type paramenter T, and is assignable to DataServiceCollection<T>
                    Type[] parms = type.GetGenericArguments();

                    if (parms != null && parms.Length == 1 && ClientTypeUtil.TypeOrElementTypeIsEntity(parms[0]))
                    {
                        // if ObservableCollection is not available dataServiceCollection will be null
                        Type dataServiceCollection = WebUtil.GetDataServiceCollectionOfT(parms);
                        if (dataServiceCollection != null && dataServiceCollection.IsAssignableFrom(type))
                        {
                            result = true;
                            break;
                        }
                    }
                }

                type = type.GetBaseType();
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!knownObservableCollectionTypes.ContainsKey(collectionType))
                {
                    knownObservableCollectionTypes[collectionType] = result ? TrueObject : FalseObject;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return result;
        }
Ejemplo n.º 40
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();
            }
        }
Ejemplo n.º 41
0
        /// <summary>
        /// Determine if the specified type is an entity type.
        /// </summary>
        /// <param name="type">An object type specifier.</param>
        /// <param name="model">The client model.</param>
        /// <returns>true if the type is an entity type; otherwise false.</returns>
        internal static bool IsEntityType(Type type, ClientEdmModel model)
        {
            Debug.Assert(type != null, "Argument 'type' cannot be null.");

            metadataCacheLock.EnterReadLock();
            try
            {
                if (knownNonEntityTypes.Contains(type))
                {
                    return false;
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bool isEntityType;
            try
            {
                if (BindingEntityInfo.IsDataServiceCollection(type, model))
                {
                    return false;
                }

                isEntityType = ClientTypeUtil.TypeOrElementTypeIsEntity(type);
            }
            catch (InvalidOperationException)
            {
                isEntityType = false;
            }

            if (!isEntityType)
            {
                metadataCacheLock.EnterWriteLock();
                try
                {
                    if (!knownNonEntityTypes.Contains(type))
                    {
                        knownNonEntityTypes.Add(type);
                    }
                }
                finally
                {
                    metadataCacheLock.ExitWriteLock();
                }
            }

            return isEntityType;
        }
Ejemplo n.º 42
0
        private string ConvertToEscapedUriValue(string paramName, object value)
        {
            Debug.Assert(!string.IsNullOrEmpty(paramName), "!string.IsNullOrEmpty(paramName)");
            Object valueInODataFormat = null;

            // Literal values with single quotes need special escaping due to System.Uri changes in behavior between .NET 4.0 and 4.5.
            // We need to ensure that our escaped values do not change between those versions, so we need to escape values differently when they could contain single quotes.
            bool needsSpecialEscaping = false;

            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");

                    switch (edmType.TypeKind)
                    {
                    case EdmTypeKind.Primitive:
                        valueInODataFormat   = value;
                        needsSpecialEscaping = true;
                        break;

                    case EdmTypeKind.Enum:
                    {
                        ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType);
                        string     typeNameInEdm            = this.requestInfo.GetServerTypeName(model.GetClientTypeAnnotation(edmType));
                        MemberInfo member = typeAnnotation.ElementType.GetMember(value.ToString()).FirstOrDefault();
                        if (member == null)
                        {
                            throw new NotSupportedException(Strings.Serializer_InvalidEnumMemberValue(typeAnnotation.ElementType.Name, value.ToString()));
                        }

                        string memberValue = ClientTypeUtil.GetServerDefinedName(member);

                        valueInODataFormat   = new ODataEnumValue(memberValue, typeNameInEdm ?? typeAnnotation.ElementTypeName);
                        needsSpecialEscaping = true;
                    }

                    break;

                    case EdmTypeKind.Complex:
                    {
                        ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType);
                        Debug.Assert(typeAnnotation != null, "typeAnnotation != null");
                        valueInODataFormat = this.propertyConverter.CreateODataComplexValue(typeAnnotation.ElementType, value, null /*propertyName*/, false /*isCollectionItemType*/, null /*visitedComplexTypeObjects*/);

                        // When using JsonVerbose to format query string parameters for Actions,
                        // we cannot write out Complex values in the URI without the type name of the complex type in the JSON payload.
                        // If this value is null, the client has to set the ResolveName property on the DataServiceContext instance.
                        ODataComplexValue complexValue = (ODataComplexValue)valueInODataFormat;
                        SerializationTypeNameAnnotation serializedTypeNameAnnotation = complexValue.GetAnnotation <SerializationTypeNameAnnotation>();
                        if (serializedTypeNameAnnotation == null || string.IsNullOrEmpty(serializedTypeNameAnnotation.TypeName))
                        {
                            throw Error.InvalidOperation(Strings.DataServiceException_GeneralError);
                        }
                    }

                    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");

                        switch (itemTypeAnnotation.EdmType.TypeKind)
                        {
                        // We only support primitive, Enum or complex type as a collection item type.
                        case EdmTypeKind.Primitive:
                        case EdmTypeKind.Enum:
                        case EdmTypeKind.Complex:
                            break;

                        default:
                            throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(paramName, itemTypeAnnotation.EdmType.TypeKind));
                        }

                        valueInODataFormat = this.propertyConverter.CreateODataCollection(
                            itemTypeAnnotation.ElementType,
                            null /*propertyName*/,
                            value,
                            null /*visitedComplexTypeObjects*/);
                        break;

                    default:
                        // EdmTypeKind.Entity
                        // EdmTypeKind.Row
                        // EdmTypeKind.EntityReference
                        throw new NotSupportedException(Strings.Serializer_InvalidParameterType(paramName, edmType.TypeKind));
                    }
                }

                Debug.Assert(valueInODataFormat != null, "valueInODataFormat != null");
            }

            // When calling Execute() to invoke an Action, the client doesn't support parsing the target url
            // to determine which IEdmOperationImport to pass to the ODL writer. So the ODL writer is
            // serializing the parameter payload without metadata. Setting the model to null so ODL doesn't
            // do unecessary validations when writing without metadata.
            string literal = ODataUriUtils.ConvertToUriLiteral(valueInODataFormat, CommonUtil.ConvertToODataVersion(this.requestInfo.MaxProtocolVersionAsVersion), null /* edmModel */);

            // The value from ConvertToUriValue will not be escaped, but will already contain literal delimiters like single quotes, so we
            // need to use our own escape method that will preserve those characters instead of directly calling Uri.EscapeDataString that may escape them.
            // This is only necessary for primitives and nulls because the other structures are serialized using the JSON format and it uses double quotes
            // which have always been escaped.
            if (needsSpecialEscaping)
            {
                return(DataStringEscapeBuilder.EscapeDataString(literal));
            }

            return(Uri.EscapeDataString(literal));
        }
Ejemplo n.º 43
0
        /// <summary>
        /// Tries to get the value of a property and corresponding BindingPropertyInfo or ClientPropertyAnnotation if the property exists
        /// </summary>
        /// <param name="source">Source object whose property needs to be read</param>
        /// <param name="sourceProperty">Name of the source object property</param>
        /// <param name="model">The client model.</param>
        /// <param name="bindingPropertyInfo">BindingPropertyInfo corresponding to <paramref name="sourceProperty"/></param>
        /// <param name="clientProperty">Instance of ClientProperty corresponding to <paramref name="sourceProperty"/></param>
        /// <param name="propertyValue">Value of the property</param>
        /// <returns>true if the property exists and the value was read; otherwise false.</returns>
        internal static bool TryGetPropertyValue(object source, string sourceProperty, ClientEdmModel model, out BindingPropertyInfo bindingPropertyInfo, out ClientPropertyAnnotation clientProperty, out object propertyValue)
        {
            Type sourceType = source.GetType();

            bindingPropertyInfo = BindingEntityInfo.GetObservableProperties(sourceType, model)
                                                   .SingleOrDefault(x => x.PropertyInfo.PropertyName == sourceProperty);

            bool propertyFound = bindingPropertyInfo != null;

            // bindingPropertyInfo is null for primitive properties.
            if (!propertyFound)
            {
                clientProperty = BindingEntityInfo.GetClientType(sourceType, model)
                    .GetProperty(sourceProperty, true);

                propertyFound = clientProperty != null;
                if (!propertyFound)
                {
                    propertyValue = null;
                }
                else
                {
                    propertyValue = clientProperty.GetValue(source);
                }
            }
            else
            {
                clientProperty = null;
                propertyValue = bindingPropertyInfo.PropertyInfo.GetValue(source);
            }

            return propertyFound;
        }
Ejemplo n.º 44
0
        /// <summary>
        /// Tries to get the value of a property and corresponding BindingPropertyInfo or ClientPropertyAnnotation if the property exists
        /// </summary>
        /// <param name="source">Source object whose property needs to be read</param>
        /// <param name="sourceProperty">Name of the source object property</param>
        /// <param name="model">The client model.</param>
        /// <param name="bindingPropertyInfo">BindingPropertyInfo corresponding to <paramref name="sourceProperty"/></param>
        /// <param name="clientProperty">Instance of ClientProperty corresponding to <paramref name="sourceProperty"/></param>
        /// <param name="propertyValue">Value of the property</param>
        /// <returns>true if the property exists and the value was read; otherwise false.</returns>
        internal static bool TryGetPropertyValue(object source, string sourceProperty, ClientEdmModel model, out BindingPropertyInfo bindingPropertyInfo, out ClientPropertyAnnotation clientProperty, out object propertyValue)
        {
            Type sourceType = source.GetType();

            bindingPropertyInfo = BindingEntityInfo.GetObservableProperties(sourceType, model)
                                  .SingleOrDefault(x => x.PropertyInfo.PropertyName == sourceProperty);

            bool propertyFound = bindingPropertyInfo != null;

            // bindingPropertyInfo is null for primitive properties.
            if (!propertyFound)
            {
                clientProperty = BindingEntityInfo.GetClientType(sourceType, model)
                                 .GetProperty(sourceProperty, true);

                propertyFound = clientProperty != null;
                if (!propertyFound)
                {
                    propertyValue = null;
                }
                else
                {
                    propertyValue = clientProperty.GetValue(source);
                }
            }
            else
            {
                clientProperty = null;
                propertyValue  = bindingPropertyInfo.PropertyInfo.GetValue(source);
            }

            return(propertyFound);
        }
Ejemplo n.º 45
0
        /// <summary>Obtain binding info corresponding to a given type</summary>
        /// <param name="entityType">Type for which to obtain information</param>
        /// <param name="model">The client model.</param>
        /// <returns>Info about the <paramref name="entityType"/></returns>
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType, ClientEdmModel model)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also.
            // EntitySetAttribute does not allow multiples, so there can be at most 1 instance on the type.
            EntitySetAttribute entitySetAttribute = (EntitySetAttribute)entityType.GetCustomAttributes(typeof(EntitySetAttribute), true).SingleOrDefault();

            // There must be exactly one (unambiguous) EntitySetAttribute attribute.
            bindingEntityInfo.EntitySet = entitySetAttribute != null ? entitySetAttribute.EntitySet : null;
            bindingEntityInfo.ClientType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityType));

            foreach (ClientPropertyAnnotation p in bindingEntityInfo.ClientType.Properties())
            {
                BindingPropertyInfo bpi = null;
                Type propertyType = p.PropertyType;

                if (p.IsStreamLinkProperty)
                {
                    // DataServiceStreamLink is not mutable externally
                    // It implements INPC to notify controls about our updates
                    // We should ignore its events since we are the only one updating it.
                    continue;
                }
                else if (p.IsPrimitiveOrEnumOrComplexCollection)
                {
                    Debug.Assert(!BindingEntityInfo.IsDataServiceCollection(propertyType, model), "DataServiceCollection cannot be the type that backs collections of primitives or complex types.");
                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection };
                }
                else if (p.IsEntityCollection)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType, model))
                    {
                        bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindDataServiceCollection };
                    }
                }
                else if (BindingEntityInfo.IsEntityType(propertyType, model))
                {
                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindEntity };
                }
                else if (BindingEntityInfo.CanBeComplexType(propertyType))
                {
                    // Add complex types and nothing else.
                    Debug.Assert(!p.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindComplex };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    // For entity types, all of the above types of properties are interesting.
                    // For complex types, only observe collections and complex type properties.
                    if (bindingEntityInfo.ClientType.IsEntityType ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return bindingEntityInfo;
        }
Ejemplo n.º 46
0
 /// <summary>Gets entity set corresponding to a given type</summary>
 /// <param name="entityType">Intput type</param>
 /// <param name="model">The client model.</param>
 /// <returns>Entity set name for the type</returns>
 private static string GetEntitySetAttribute(Type entityType, ClientEdmModel model)
 {
     return(GetBindingEntityInfoFor(entityType, model).EntitySet);
 }
Ejemplo n.º 47
0
 /// <summary>Gets entity set corresponding to a given type</summary>
 /// <param name="entityType">Intput type</param>
 /// <param name="model">The client model.</param>
 /// <returns>Entity set name for the type</returns>
 private static string GetEntitySetAttribute(Type entityType, ClientEdmModel model)
 {
     return GetBindingEntityInfoFor(entityType, model).EntitySet;
 }
Ejemplo n.º 48
0
 /// <summary>Gets the ClientType corresponding to the given type</summary>
 /// <param name="entityType">Input type</param>
 /// <param name="model">The client model.</param>
 /// <returns>Corresponding ClientType</returns>
 internal static ClientTypeAnnotation GetClientType(Type entityType, ClientEdmModel model)
 {
     return(GetBindingEntityInfoFor(entityType, model).ClientType);
 }
Ejemplo n.º 49
0
 /// <summary>Obtain binding info corresponding to a given type</summary>
 /// <param name="entityType">Type for which to obtain information</param>
 /// <param name="model">the client model.</param>
 /// <returns>Info about the <paramref name="entityType"/></returns>
 internal static IList<BindingPropertyInfo> GetObservableProperties(Type entityType, ClientEdmModel model)
 {
     return GetBindingEntityInfoFor(entityType, model).ObservableProperties;
 }
        /// <summary>
        /// Validates the specified <paramref name="property"/> matches 
        /// the parsed <paramref name="atomProperty"/>.
        /// </summary>
        /// <param name="property">Property as understood by the type system.</param>
        /// <param name="atomProperty">Property as parsed.</param>
        /// <param name="model">Client model.</param>
        /// <param name="performEntityCheck">whether to do the entity check or not.</param>
        internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataProperty atomProperty, ClientEdmModel model, bool performEntityCheck)
        {
            Debug.Assert(property != null, "property != null");
            Debug.Assert(atomProperty != null, "atomProperty != null");

            ODataFeed feed = atomProperty.Value as ODataFeed;
            ODataEntry entry = atomProperty.Value as ODataEntry;

            if (property.IsKnownType && (feed != null || entry != null))
            {
                throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkLocalSimple);
            }

            Type propertyType = null;
            if (feed != null)
            {
                // We need to fail if the payload states that the property is a navigation collection property
                // and in the client, the property is not a collection property.
                if (!property.IsEntityCollection)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName));
                }

                propertyType = property.EntityCollectionItemType;
            }

            if (entry != null)
            {
                if (property.IsEntityCollection)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName));
                }

                propertyType = property.PropertyType;
            }

            // If the server type and the client type does not match, we need to throw.
            // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa
            if (propertyType != null && performEntityCheck)
            {
                if (!ClientTypeUtil.TypeIsEntity(propertyType, model))
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString()));
                }
            }
        }
Ejemplo n.º 51
0
 /// <summary>Gets the ClientType corresponding to the given type</summary>
 /// <param name="entityType">Input type</param>
 /// <param name="model">The client model.</param>
 /// <returns>Corresponding ClientType</returns>
 internal static ClientTypeAnnotation GetClientType(Type entityType, ClientEdmModel model)
 {
     return GetBindingEntityInfoFor(entityType, model).ClientType;
 }
Ejemplo n.º 52
0
        /// <summary>
        /// Creates and returns an ODataComplexValue from the given value.
        /// </summary>
        /// <param name="complexType">The value type.</param>
        /// <param name="value">The complex value.</param>
        /// <param name="propertyName">If the value is a property, then it represents the name of the property. Can be null, for non-property.</param>
        /// <param name="isCollectionItem">True, if the value is an item in a collection, false otherwise.</param>
        /// <param name="visitedComplexTypeObjects">Set of instances of complex types encountered in the hierarchy. Used to detect cycles.</param>
        /// <returns>An ODataComplexValue representing the given value.</returns>
        internal ODataComplexValue CreateODataComplexValue(Type complexType, object value, string propertyName, bool isCollectionItem, HashSet <object> visitedComplexTypeObjects)
        {
            Debug.Assert(complexType != null, "complexType != null");
            Debug.Assert(value != null || !isCollectionItem, "Collection items must not be null");

            ClientEdmModel       model = this.requestInfo.Model;
            ClientTypeAnnotation complexTypeAnnotation = model.GetClientTypeAnnotation(complexType);

            Debug.Assert(complexTypeAnnotation != null, "complexTypeAnnotation != null");
            Debug.Assert(!complexTypeAnnotation.IsEntityType, "Unexpected entity");

            // Handle null values for complex types by putting m:null="true"
            if (value == null)
            {
                Debug.Assert(!isCollectionItem, "Null collection items are not supported. Should have already been checked.");
                return(null);
            }

            if (visitedComplexTypeObjects == null)
            {
                visitedComplexTypeObjects = new HashSet <object>(ReferenceEqualityComparer <object> .Instance);
            }
            else if (visitedComplexTypeObjects.Contains(value))
            {
                if (propertyName != null)
                {
                    throw Error.InvalidOperation(Strings.Serializer_LoopsNotAllowedInComplexTypes(propertyName));
                }
                else
                {
                    Debug.Assert(complexTypeAnnotation.ElementTypeName != null, "complexTypeAnnotation.ElementTypeName != null");
                    throw Error.InvalidOperation(Strings.Serializer_LoopsNotAllowedInNonPropertyComplexTypes(complexTypeAnnotation.ElementTypeName));
                }
            }

            visitedComplexTypeObjects.Add(value);
            ODataComplexValue odataComplexValue = new ODataComplexValue();

            // When TypeName is set, it causes validation to occur when ODataLib writes out the collection. Part of the validation ensures that all items
            // in the collection are exactly the same type, no derived types are allowed. In the released WCF Data Services 5.0 implementation, we don't set
            // TypeName here, so that validation does not occur, therefore we will set this value only for JSON Light, so we don't break existing code.
            if (!this.requestInfo.Format.UsingAtom)
            {
                odataComplexValue.TypeName = complexTypeAnnotation.ElementTypeName;
            }

            string serverTypeName = this.requestInfo.GetServerTypeName(complexTypeAnnotation);

            // If this complex type is a collection item don't put type name on each item
            if (!isCollectionItem)
            {
                odataComplexValue.SetAnnotation(new SerializationTypeNameAnnotation {
                    TypeName = serverTypeName
                });
            }

            odataComplexValue.Properties = this.PopulateProperties(value, serverTypeName, complexTypeAnnotation.PropertiesToSerialize(), visitedComplexTypeObjects);

            visitedComplexTypeObjects.Remove(value);
            return(odataComplexValue);
        }
Ejemplo n.º 53
0
        /// <summary>
        /// Get the entity set name for the target entity object.
        /// </summary>
        /// <param name="target">An entity object.</param>
        /// <param name="targetEntitySet">The 'currently known' entity set name for the target object.</param>
        /// <param name="model">The client model.</param>
        /// <returns>The entity set name for the target object.</returns>
        /// <remarks>
        /// Allow user code to provide the entity set name. If user code does not provide the entity set name, then 
        /// this method will get the entity set name from the value of the EntitySetAttribute.
        /// The 'currently known' entity set name for top level collections can be provided through OEC constructor
        /// </remarks>
        internal static string GetEntitySet(
            object target,
            string targetEntitySet,
            ClientEdmModel model)
        {
            Debug.Assert(target != null, "Argument 'target' cannot be null.");
            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType(), model), "Argument 'target' must be an entity type.");

            // Here's the rules in order of priority for resolving entity set name
            // 1. EntitySet name passed in the constructor or extension methods of DataServiceCollection
            // 2. EntitySet name specified in the EntitySet attribute by the code gen. {Remember this attribute is
            //    not generated in case of MEST)
            if (!String.IsNullOrEmpty(targetEntitySet))
            {
                return targetEntitySet;
            }
            else
            {
                // If there is not a 'currently known' entity set name to validate against, then there must be 
                // EntitySet attribute on the entity type
                return BindingEntityInfo.GetEntitySetAttribute(target.GetType(), model);
            }
        }
Ejemplo n.º 54
0
 /// <summary>
 /// Creates a new instance of EntityTracker class which tracks all instances of entities and links tracked by the context.
 /// </summary>
 /// <param name="maxProtocolVersion">max protocol version that the client understands.</param>
 internal EntityTracker(ClientEdmModel maxProtocolVersion)
 {
     this.model = maxProtocolVersion;
 }
 /// <summary>
 /// Create a new instance of Entity descriptor.
 /// </summary>
 /// <param name="model">The client model</param>
 internal EntityDescriptor(ClientEdmModel model)
     : base(EntityStates.Unchanged)
 {
     this.Model = model;
     this.PropertiesToSerialize = new HashSet <string>(StringComparer.Ordinal);
 }
Ejemplo n.º 56
0
 /// <summary>The QueryComponents associated with this request</summary>
 /// <param name="model">The client model.</param>
 /// <returns>instance of query components</returns>
 internal abstract QueryComponents QueryComponents(ClientEdmModel model);
Ejemplo n.º 57
0
        /// <summary>
        /// Converts the object to ODataValue, the result could be null, the original primitive object, ODataNullValue,
        /// ODataEnumValue, ODataCollectionValue, ODataEntry, ODataEntityReferenceLinks, ODataEntityReferenceLinks, or
        /// a list of ODataEntry.
        /// </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:
                    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.Complex:
                    Debug.Assert(typeAnnotation != null, "typeAnnotation != null");
                    valueInODataFormat = this.propertyConverter.CreateODataComplexValue(typeAnnotation.ElementType, value, null, false, null);

                    // When using JsonVerbose to format query string parameters for Actions,
                    // we cannot write out Complex values in the URI without the type name of the complex type in the JSON payload.
                    // If this value is null, the client has to set the ResolveName property on the DataServiceContext instance.
                    ODataComplexValue complexValue = (ODataComplexValue)valueInODataFormat;
                    SerializationTypeNameAnnotation serializedTypeNameAnnotation =
                        complexValue.GetAnnotation <SerializationTypeNameAnnotation>();
                    if (serializedTypeNameAnnotation == null ||
                        string.IsNullOrEmpty(serializedTypeNameAnnotation.TypeName))
                    {
                        throw Error.InvalidOperation(Strings.DataServiceException_GeneralError);
                    }

                    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.Entity:
                    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);
        }
Ejemplo n.º 58
0
 /// <summary>
 /// Creates a new instance of EntityTracker class which tracks all instances of entities and links tracked by the context.
 /// </summary>
 /// <param name="maxProtocolVersion">max protocol version that the client understands.</param>
 internal EntityTracker(ClientEdmModel maxProtocolVersion)
 {
     this.model = maxProtocolVersion;
 }
Ejemplo n.º 59
0
        /// <summary>
        /// Writes the body operation parameters associated with a ServiceAction. For each BodyOperationParameter:
        /// 1. calls ODataPropertyConverter  to convert CLR object into ODataValue/primitive values.
        /// 2. then calls ODataParameterWriter to write the ODataValue/primitive values.
        /// </summary>
        /// <param name="operationParameters">The list of operation parameters to write.</param>
        /// <param name="requestMessage">The OData request message used to write the operation parameters.</param>
        internal void WriteBodyOperationParameters(List <BodyOperationParameter> operationParameters, ODataRequestMessageWrapper requestMessage)
        {
            Debug.Assert(requestMessage != null, "requestMessage != null");
            Debug.Assert(operationParameters != null, "operationParameters != null");
            Debug.Assert(operationParameters.Any(), "operationParameters.Any()");

            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, true /*isParameterPayload*/))
            {
                ODataParameterWriter parameterWriter = messageWriter.CreateODataParameterWriter(null);
                parameterWriter.WriteStart();

                foreach (BodyOperationParameter operationParameter in operationParameters)
                {
                    if (operationParameter.Value == null)
                    {
                        parameterWriter.WriteValue(operationParameter.Name, operationParameter.Value);
                    }
                    else
                    {
                        ClientEdmModel model   = this.requestInfo.Model;
                        IEdmType       edmType = model.GetOrCreateEdmType(operationParameter.Value.GetType());
                        Debug.Assert(edmType != null, "edmType != null");

                        switch (edmType.TypeKind)
                        {
                        case EdmTypeKind.Collection:
                        {
                            this.WriteCollectionValueInBodyOperationParameter(parameterWriter, operationParameter, (IEdmCollectionType)edmType);
                            break;
                        }

                        case EdmTypeKind.Complex:
                        case EdmTypeKind.Entity:
                        {
                            Debug.Assert(model.GetClientTypeAnnotation(edmType).ElementType != null, "model.GetClientTypeAnnotation(edmType).ElementType != null");
                            ODataResourceWrapper entry = this.CreateODataResourceFromEntityOperationParameter(model.GetClientTypeAnnotation(edmType), operationParameter.Value);
                            Debug.Assert(entry != null, "entry != null");
                            var entryWriter = parameterWriter.CreateResourceWriter(operationParameter.Name);
                            ODataWriterHelper.WriteResource(entryWriter, entry);
                            break;
                        }

                        case EdmTypeKind.Primitive:
                            object primitiveValue = ODataPropertyConverter.ConvertPrimitiveValueToRecognizedODataType(operationParameter.Value, operationParameter.Value.GetType());
                            parameterWriter.WriteValue(operationParameter.Name, primitiveValue);
                            break;

                        case EdmTypeKind.Enum:
                            ODataEnumValue tmp = this.propertyConverter.CreateODataEnumValue(
                                model.GetClientTypeAnnotation(edmType).ElementType,
                                operationParameter.Value,
                                false);
                            parameterWriter.WriteValue(operationParameter.Name, tmp);

                            break;

                        default:
                            // EdmTypeKind.Row
                            // EdmTypeKind.EntityReference
                            throw new NotSupportedException(Strings.Serializer_InvalidParameterType(operationParameter.Name, edmType.TypeKind));
                        }
                    } // else
                }     // foreach

                parameterWriter.WriteEnd();
                parameterWriter.Flush();
            }
        }