public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
        {
            EdmModel model = null;
            if (this.InnerHandler != null)
            {
                model = await this.InnerHandler.GetModelAsync(context, cancellationToken) as EdmModel;
            }

            if (model == null)
            {
                // We don't plan to extend an empty model with operations.
                return null;
            }

            this.ScanForOperations();

            string existingNamespace = null;
            if (model.DeclaredNamespaces != null)
            {
                existingNamespace = model.DeclaredNamespaces.FirstOrDefault();
            }

            this.BuildOperations(model, existingNamespace);
            return model;
        }
        /// <summary>
        /// Asynchronously executes the model flow.
        /// </summary>
        /// <param name="context">
        /// The model context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a domain model.
        /// </returns>
        public async Task<IEdmModel> GetModelAsync(
            ModelContext context,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            // STEP 1: produce model
            var producer = context.GetHookPoint<IModelProducer>();
            if (producer != null)
            {
                context.Model = await producer.ProduceModelAsync(
                    context, cancellationToken);
            }

            if (context.Model == null)
            {
                context.Model = new EdmModel();
            }

            // STEP 2: extend model
            var extenders = context.GetHookPoints<IModelExtender>();
            foreach (var extender in extenders)
            {
                await extender.ExtendModelAsync(context, cancellationToken);
            }

            return context.Model;
        }
        private void ExtendModel(ModelContext context)
        {
            var method = this.targetType.GetQualifiedMethod("OnModelExtending");
            var returnType = typeof(EdmModel);

            if (method == null || method.ReturnType != returnType)
            {
                return;
            }

            object target = null;
            if (!method.IsStatic)
            {
                target = context.DomainContext.GetProperty(targetType.AssemblyQualifiedName);
                if (target == null || !targetType.IsInstanceOfType(target))
                {
                    return;
                }
            }

            var parameters = method.GetParameters();
            if (parameters.Length != 1 || parameters[0].ParameterType != returnType)
            {
                return;
            }

            var model = context.Model;
            var result = (EdmModel)method.Invoke(target, new object[] { model });
            if (result != null && result != model)
            {
                context.Model = result;
            }
        }
        public void ExtendModelAsync_UpdatesModel_IfHasOnModelCreatingMethod(Type type)
        {
            // Arrange
            var domain = Activator.CreateInstance(type);
            var extender = new ConventionalModelExtender(type);
            var domainConfig = new DomainConfiguration();
            domainConfig.EnsureCommitted();
            var domainContext = new DomainContext(domainConfig);
            domainContext.SetProperty(type.AssemblyQualifiedName, domain);
            var model = GetModel();
            var context = new ModelContext(domainContext) { Model = model };

            // Act
            extender.ExtendModelAsync(context, new CancellationToken());

            // Assert
            Assert.Same(model, context.Model);
            var operations = model.SchemaElements.OfType<IEdmOperation>();
            Assert.Single(operations);
            var operation = operations.Single();
            Assert.True(operation.IsBound);
            Assert.True(operation.IsFunction());
            Assert.Equal("MostExpensive", operation.Name);
            Assert.Equal("ns", operation.Namespace);
        }
        /// <inheritdoc/>
        public Task ExtendModelAsync(
            ModelContext context,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(context);
            var model = context.Model;
            foreach (var entitySetProperty in this.AddedEntitySets)
            {
                var container = model.EntityContainer as EdmEntityContainer;
                var elementType = entitySetProperty
                    .PropertyType.GetGenericArguments()[0];
                var entityType = context.Model.SchemaElements
                    .OfType<IEdmEntityType>()
                    .SingleOrDefault(se => se.Name == elementType.Name);
                if (entityType == null)
                {
                    // TODO GitHubIssue#33 : Add new entity type representing entity shape
                    continue;
                }

                container.AddEntitySet(entitySetProperty.Name, entityType);
            }

            return Task.FromResult<object>(null);
        }
        public Task ExtendModelAsync(
            ModelContext context,
            CancellationToken cancellationToken)
        {
            var model = context.Model;
            var entityContainer = model.EntityContainer as EdmEntityContainer;

            foreach (ActionMethodInfo actionInfo in this.ActionInfos)
            {
                var returnTypeReference = ConventionalActionProvider.GetReturnTypeReference(actionInfo.Method.ReturnType);
                var action = new EdmAction(entityContainer.Namespace, actionInfo.ActionName, returnTypeReference);

                foreach (ParameterInfo parameter in actionInfo.Method.GetParameters())
                {
                    EdmOperationParameter actionParam = new EdmOperationParameter(
                        action,
                        parameter.Name,
                        ConventionalActionProvider.GetTypeReference(parameter.ParameterType));

                    action.AddParameter(actionParam);
                }

                model.AddElement(action);

                if (!action.IsBound)
                {
                    EdmActionImport actionImport = new EdmActionImport(entityContainer, action.Name, action);
                    entityContainer.AddElement(actionImport);
                }
            }
            return Task.FromResult<object>(null);
        }
Example #7
0
 public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
 {
     var model = new EdmModel();
     var dummyType = new EdmEntityType("NS", "Dummy");
     model.AddElement(dummyType);
     var container = new EdmEntityContainer("NS", "DefaultContainer");
     container.AddEntitySet("Test", dummyType);
     model.AddElement(container);
     return Task.FromResult((IEdmModel) model);
 }
 public async Task ExtendModelAsync(
     ModelContext context,
     CancellationToken cancellationToken)
 {
     var entityType = new EdmEntityType(
         "TestNamespace", "TestName" + _index);
     context.Model.AddElement(entityType);
     (context.Model.EntityContainer as EdmEntityContainer)
         .AddEntitySet("TestEntitySet" + _index, entityType);
     await Task.Yield();
 }
 public Task<EdmModel> ProduceModelAsync(
     ModelContext context,
     CancellationToken cancellationToken)
 {
     var model = new EdmModel();
     var entityType = new EdmEntityType(
         "TestNamespace", "TestName");
     var entityContainer = new EdmEntityContainer(
         "TestNamespace", "Entities");
     entityContainer.AddEntitySet("TestEntitySet", entityType);
     model.AddElement(entityType);
     model.AddElement(entityContainer);
     return Task.FromResult(model);
 }
Example #10
0
        /// <summary>
        /// This class will not real build a model, but only get entity set name and entity map from data source
        /// Then pass the information to publisher layer to build the model.
        /// </summary>
        /// <param name="context">
        /// The context for processing
        /// </param>
        /// <param name="cancellationToken">
        /// An optional cancellation token.
        /// </param>
        /// <returns>
        /// Always a null model.
        /// </returns>
        public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

#if EF7
            var dbContext = context.ApiContext.GetApiService<DbContext>();
            context.ResourceSetTypeMap = dbContext.GetType().GetProperties()
                .Where(e => e.PropertyType.FindGenericType(typeof(DbSet<>)) != null)
                .ToDictionary(e => e.Name, e => e.PropertyType.GetGenericArguments()[0]);
            context.ResourceTypeKeyPropertiesMap = dbContext.Model.GetEntityTypes().ToDictionary(
                e => e.ClrType,
                e => ((ICollection<PropertyInfo>)
                    e.FindPrimaryKey().Properties.Select(p => e.ClrType.GetProperty(p.Name)).ToList()));
#else
            var resourceSetTypeMap = new Dictionary<string, Type>();
            var resourceTypeKeyPropertiesMap = new Dictionary<Type, ICollection<PropertyInfo>>();
            var dbContext = context.ServiceProvider.GetService<DbContext>();

            var efModel = (dbContext as IObjectContextAdapter).ObjectContext.MetadataWorkspace;
            var efEntityContainer = efModel.GetItems<EntityContainer>(DataSpace.CSpace).Single();
            var itemCollection = (ObjectItemCollection)efModel.GetItemCollection(DataSpace.OSpace);

            foreach (var efEntitySet in efEntityContainer.EntitySets)
            {
                var efEntityType = efEntitySet.ElementType;
                var objectSpaceType = efModel.GetObjectSpaceType(efEntityType);
                Type clrType = itemCollection.GetClrType(objectSpaceType);

                // As entity set name and type map
                resourceSetTypeMap.Add(efEntitySet.Name, clrType);

                ICollection<PropertyInfo> keyProperties = new List<PropertyInfo>();
                foreach (var property in efEntityType.KeyProperties)
                {
                    keyProperties.Add(clrType.GetProperty(property.Name));
                }

                resourceTypeKeyPropertiesMap.Add(clrType, keyProperties);
            }

            context.ResourceSetTypeMap = resourceSetTypeMap;
            context.ResourceTypeKeyPropertiesMap = resourceTypeKeyPropertiesMap;
#endif
            if (InnerModelBuilder != null)
            {
                return InnerModelBuilder.GetModelAsync(context, cancellationToken);
            }

            return Task.FromResult<IEdmModel>(null);
        }
        public void ExtendModelAsync_DoesntUpdatesModel_IfWithoutOnModelCreatingMethod()
        {
            // Arrange
            var domain = new AnyDomain();
            var type = domain.GetType();
            var extender = new ConventionalModelExtender(type);
            var domainConfig = new DomainConfiguration();
            domainConfig.EnsureCommitted();
            var domainContext = new DomainContext(domainConfig);
            domainContext.SetProperty(type.AssemblyQualifiedName, domain);
            var model = GetModel();
            var context = new ModelContext(domainContext) { Model = model };

            // Act
            extender.ExtendModelAsync(context, new CancellationToken());

            // Assert
            Assert.Same(model, context.Model);
            Assert.Empty(model.SchemaElements.OfType<IEdmOperation>());
        }
 public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
 {
     var modelBuilder = new ODataConventionModelBuilder();
     modelBuilder.Namespace = "Microsoft.OData.Service.Sample.TrippinInMemory.Models";
     modelBuilder.EntitySet<Person>("People");
     modelBuilder.EntitySet<Airline>("Airlines");
     modelBuilder.EntitySet<Airport>("Airports");
     return Task.FromResult(modelBuilder.GetEdmModel());
 }
        /// <inheritdoc/>
        public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
        {
            // This means user build a model with customized model builder registered as inner most
            // Its element will be added to built model.
            IEdmModel innerModel = null;
            if (InnerModelBuilder != null)
            {
                innerModel = await InnerModelBuilder.GetModelAsync(context, cancellationToken);
            }

            var entitySetTypeMap = context.ResourceSetTypeMap;
            if (entitySetTypeMap == null || entitySetTypeMap.Count == 0)
            {
                return innerModel;
            }

            // Collection of entity type and set name is set by EF now,
            // and EF model producer will not build model any more
            // Web Api OData conversion model built is been used here,
            // refer to Web Api OData document for the detail conversions been used for model built.
            var builder = new ODataConventionModelBuilder();

            // This namespace is used by container
            builder.Namespace = entitySetTypeMap.First().Value.Namespace;

            MethodInfo method = typeof(ODataConventionModelBuilder)
                .GetMethod("EntitySet", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);

            foreach (var pair in entitySetTypeMap)
            {
                // Build a method with the specific type argument
                var specifiedMethod = method.MakeGenericMethod(pair.Value);
                var parameters = new object[]
                {
                      pair.Key
                };

                specifiedMethod.Invoke(builder, parameters);
            }

            entitySetTypeMap.Clear();

            var entityTypeKeyPropertiesMap = context.ResourceTypeKeyPropertiesMap;
            if (entityTypeKeyPropertiesMap != null)
            {
                foreach (var pair in entityTypeKeyPropertiesMap)
                {
                    var edmTypeConfiguration = builder.GetTypeConfigurationOrNull(pair.Key) as EntityTypeConfiguration;
                    if (edmTypeConfiguration == null)
                    {
                        continue;
                    }

                    foreach (var property in pair.Value)
                    {
                        edmTypeConfiguration.HasKey(property);
                    }
                }

                entityTypeKeyPropertiesMap.Clear();
            }

            var model = (EdmModel)builder.GetEdmModel();

            // Add all Inner model content into existing model
            // When WebApi OData make conversion model builder accept an existing model, this can be removed.
            if (innerModel != null)
            {
                foreach (var element in innerModel.SchemaElements)
                {
                    if (!(element is EdmEntityContainer))
                    {
                        model.AddElement(element);
                    }
                }

                foreach (var annotation in innerModel.VocabularyAnnotations)
                {
                    model.AddVocabularyAnnotation(annotation);
                }

                var entityContainer = (EdmEntityContainer)model.EntityContainer;
                var innerEntityContainer = (EdmEntityContainer)innerModel.EntityContainer;
                if (innerEntityContainer != null)
                {
                    foreach (var entityset in innerEntityContainer.EntitySets())
                    {
                        if (entityContainer.FindEntitySet(entityset.Name) == null)
                        {
                            entityContainer.AddEntitySet(entityset.Name, entityset.EntityType());
                        }
                    }

                    foreach (var singleton in innerEntityContainer.Singletons())
                    {
                        if (entityContainer.FindEntitySet(singleton.Name) == null)
                        {
                            entityContainer.AddSingleton(singleton.Name, singleton.EntityType());
                        }
                    }

                    foreach (var operation in innerEntityContainer.OperationImports())
                    {
                        if (entityContainer.FindOperationImports(operation.Name) == null)
                        {
                            if (operation.IsFunctionImport())
                            {
                                entityContainer.AddFunctionImport(
                                    operation.Name, (EdmFunction)operation.Operation, operation.EntitySet);
                            }
                            else
                            {
                                entityContainer.AddActionImport(
                                    operation.Name, (EdmAction)operation.Operation, operation.EntitySet);
                            }
                        }
                    }
                }
            }

            return model;
        }
            public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
            {
                await Task.Delay(30);

                Interlocked.Increment(ref CalledCount);
                return new EdmModel();
            }
Example #15
0
        /// <summary>
        /// Asynchronously produces a base model.
        /// </summary>
        /// <param name="context">
        /// The model context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is the base model.
        /// </returns>
        public Task<EdmModel> ProduceModelAsync(
            ModelContext context,
            CancellationToken cancellationToken)
        {
            var model = new EdmModel();
            var domainContext = context.DomainContext;
            var dbContext = domainContext.GetProperty<DbContext>("DbContext");
            var elementMap = new Dictionary<IAnnotatable, IEdmElement>();
            var efModel = dbContext.Model;
            var namespaceName = efModel.EntityTypes
                .Select(t => t.HasClrType() ? t.ClrType.Namespace : null)
                .Where(t => t != null)
                .GroupBy(nameSpace => nameSpace)
                .Select(group => new
                {
                    NameSpace = group.Key,
                    Count = group.Count(),
                })
                .OrderByDescending(nsItem => nsItem.Count)
                .Select(nsItem => nsItem.NameSpace)
                .FirstOrDefault();
            if (namespaceName == null)
            {
                // When dbContext has not a namespace, just use its type name as namespace.
                namespaceName = dbContext.GetType().Namespace ?? dbContext.GetType().Name;
            }

            var entityTypes = efModel.EntityTypes;
            var entityContainer = new EdmEntityContainer(
                namespaceName, "Container");

            var dbSetProperties = dbContext.GetType().
                GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).
                Where(e => e.PropertyType.IsGenericType && e.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)).
                ToDictionary(e => e.PropertyType.GetGenericArguments()[0]);

            // TODO GitHubIssue#36 : support complex and entity inheritance
            foreach (var efEntityType in entityTypes)
            {
                if (elementMap.ContainsKey(efEntityType))
                {
                    continue;
                }
                List<EdmStructuralProperty> concurrencyProperties;
                var entityType = ModelProducer.CreateEntityType(
                    efModel, efEntityType, model, out concurrencyProperties);
                model.AddElement(entityType);
                elementMap.Add(efEntityType, entityType);

                System.Reflection.PropertyInfo propInfo;
                if (dbSetProperties.TryGetValue(efEntityType.ClrType, out propInfo))
                {
                    var entitySet = entityContainer.AddEntitySet(propInfo.Name, entityType);
                    if (concurrencyProperties != null)
                    {
                        model.SetOptimisticConcurrencyAnnotation(entitySet, concurrencyProperties);
                    }
                }
            }

            foreach (var efEntityType in entityTypes)
            {
                foreach (var navi in efEntityType.GetNavigations())
                {
                    ModelProducer.AddNavigationProperties(
                        efModel, navi, model, elementMap);
                    ModelProducer.AddNavigationPropertyBindings(
                        efModel, navi, entityContainer, elementMap);
                }
            }

            // TODO GitHubIssue#36 : support function imports
            model.AddElement(entityContainer);

            return Task.FromResult(model);
        }
 /// <summary>
 /// Asynchronously extends the model.
 /// </summary>
 /// <param name="context">The context that contains the model.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <returns>The task object that represents this asynchronous operation.</returns>
 public Task ExtendModelAsync(ModelContext context, CancellationToken cancellationToken)
 {
     ExtendModel(context);
     return Task.WhenAll();
 }
Example #17
0
 public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
 {
     return Task.FromResult<IEdmModel>(model);
 }
            public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
            {
                IEdmModel innerModel = null;
                if (this.InnerHandler != null)
                {
                    innerModel = await this.InnerHandler.GetModelAsync(context, cancellationToken);
                }

                var entityType = new EdmEntityType(
                     "TestNamespace", "TestName" + _index);

                var model = innerModel as EdmModel;
                Assert.NotNull(model);

                model.AddElement(entityType);
                (model.EntityContainer as EdmEntityContainer)
                    .AddEntitySet("TestEntitySet" + _index, entityType);

                return model;
            }
            /// <inheritdoc/>
            public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
            {
                Ensure.NotNull(context, "context");

                IEdmModel modelReturned = await GetModelReturnedByInnerHandlerAsync(context, cancellationToken);
                if (modelReturned == null)
                {
                    // There is no model returned so return an empty model.
                    var emptyModel = new EdmModel();
                    emptyModel.EnsureEntityContainer(ModelCache.targetType);
                    return emptyModel;
                }

                EdmModel edmModel = modelReturned as EdmModel;
                if (edmModel == null)
                {
                    // The model returned is not an EDM model.
                    return modelReturned;
                }

                ModelCache.ScanForDeclaredPublicProperties();
                ModelCache.BuildEntitySetsAndSingletons(edmModel);
                ModelCache.AddNavigationPropertyBindings(edmModel);
                return edmModel;
            }
            public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
            {
                if (CalledCount++ == 0)
                {
                    await Task.Delay(100);
                    throw new Exception("Deliberate failure");
                }

                return new EdmModel();
            }
            private async Task<IEdmModel> GetModelReturnedByInnerHandlerAsync(
                ModelContext context, CancellationToken cancellationToken)
            {
                var innerHandler = InnerModelBuilder;
                if (innerHandler != null)
                {
                    return await innerHandler.GetModelAsync(context, cancellationToken);
                }

                return null;
            }
Example #22
0
        /// <summary>
        /// Asynchronously produces a base model.
        /// </summary>
        /// <param name="context">
        /// The model context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is the base model.
        /// </returns>
        public Task<EdmModel> ProduceModelAsync(
            ModelContext context,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(context);
            var model = new EdmModel();
            var domainContext = context.DomainContext;
            var dbContext = domainContext.GetProperty<DbContext>("DbContext");
            var elementMap = new Dictionary<MetadataItem, IEdmElement>();
            var efModel = (dbContext as IObjectContextAdapter)
                .ObjectContext.MetadataWorkspace;
            var namespaceName = efModel.GetItems<EntityType>(DataSpace.CSpace)
                .Select(t => efModel.GetObjectSpaceType(t).NamespaceName)
                .GroupBy(nameSpace => nameSpace)
                .Select(group => new
                {
                    NameSpace = group.Key,
                    Count = group.Count(),
                })
                .OrderByDescending(nsItem => nsItem.Count)
                .Select(nsItem => nsItem.NameSpace)
                .FirstOrDefault();
            if (namespaceName == null)
            {
                // When dbContext has not a namespace, just use its type name as namespace.
                namespaceName = dbContext.GetType().Namespace ?? dbContext.GetType().Name;
            }

            var efEntityContainer = efModel.GetItems<EntityContainer>(DataSpace.CSpace).Single();
            var entityContainer = new EdmEntityContainer(namespaceName, efEntityContainer.Name);
            elementMap.Add(efEntityContainer, entityContainer);

            // TODO GitHubIssue#36 : support complex and enumeration types
            foreach (var efEntitySet in efEntityContainer.EntitySets)
            {
                var efEntityType = efEntitySet.ElementType;
                if (elementMap.ContainsKey(efEntityType))
                {
                    continue;
                }

                List<EdmStructuralProperty> concurrencyProperties;
                var entityType = CreateEntityType(efModel, efEntityType, model, elementMap, out concurrencyProperties);
                model.AddElement(entityType);
                elementMap.Add(efEntityType, entityType);
                var entitySet = entityContainer.AddEntitySet(efEntitySet.Name, entityType);
                if (concurrencyProperties != null)
                {
                    model.SetOptimisticConcurrencyAnnotation(entitySet, concurrencyProperties);
                }

                elementMap.Add(efEntitySet, entitySet);
            }

            foreach (var efAssociationSet in efEntityContainer.AssociationSets)
            {
                AddNavigationProperties(efAssociationSet, elementMap);
                AddNavigationPropertyBindings(efAssociationSet, elementMap);
            }

            // TODO GitHubIssue#36 : support function imports
            model.AddElement(entityContainer);

            return Task.FromResult(model);
        }
 public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken)
 {
     throw new NotImplementedException();
 }