Exemple #1
0
        public static void Register(HttpConfiguration httpConfiguration)
        {
            ODataModelBuilder builder = new ODataConventionModelBuilder();
            builder.Namespace = "ODataV4TestService.Models";
            builder.EntitySet<Product>("Products");
            builder.EntitySet<SuppliedProduct>("SuppliedProducts");
            builder.EntitySet<Supplier>("Suppliers");
            builder.EntitySet<Product>("OtherProducts");

            builder.ComplexType<Description>();
            builder.EntityType<Product>()
                .Action("Rate")
                .Parameter<int>("Rating");

            builder.EntityType<Product>().Collection
                .Function("Best")
                .ReturnsCollectionFromEntitySet<Product>("Products");

            var funcConfig = builder
                .EntityType<Product>()
                .Function("RelatedProducts")
                .SetBindingParameter("product", builder.GetTypeConfigurationOrNull(typeof(Product)))
                //.AddParameter("start", new PrimitiveTypeConfiguration(builder, builder.GetTypeConfigurationOrNull(typeof(DateTimeOffset)), typeof(DateTimeOffset)).
                .ReturnsCollectionFromEntitySet<Product>("Products");

            funcConfig
                .Parameter<DateTimeOffset>("start");

            funcConfig
                .Parameter<DateTimeOffset>("end");

            //builder.Function("GetSalesTaxRate")
            //    .Returns<double>()
            //    .Parameter<int>("PostalCode");

            builder.EntitySet<Account>("Accounts");

            builder.EntityType<PaymentInstrument>()
                .Collection
                .Function("GetCount")
                .Returns<int>()
                .Parameter<string>("NameContains");

            var model = builder.GetEdmModel();

            var conventions = ODataRoutingConventions.CreateDefault();
            conventions.Insert(0, new AttributeRoutingConvention(model, httpConfiguration));

            var server = new BatchServer(httpConfiguration);

            httpConfiguration.MapODataServiceRoute(
                routeName: "ODataRoute",
                routePrefix: null,
                model: model,
                pathHandler: new DefaultODataPathHandler(),
                routingConventions: conventions,
                batchHandler: new DefaultODataBatchHandler(server));

            httpConfiguration.MessageHandlers.Add(new TracingMessageHandler());
        }
Exemple #2
0
        /// <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).ConfigureAwait(false);
            }

            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
                Namespace = entitySetTypeMap.First().Value.Namespace
            };

            var 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);
        }
Exemple #3
0
        public static void Register(HttpConfiguration httpConfiguration)
        {
            ODataModelBuilder builder = new ODataConventionModelBuilder();

            builder.Namespace = "ODataV4TestService.Models";
            builder.EntitySet <Product>("Products");
            builder.EntitySet <SuppliedProduct>("SuppliedProducts");
            builder.EntitySet <Supplier>("Suppliers");
            builder.EntitySet <Product>("OtherProducts");

            builder.ComplexType <Description>();
            builder.EntityType <Product>()
            .Action("Rate")
            .Parameter <int>("Rating");

            builder.EntityType <Product>().Collection
            .Function("Best")
            .ReturnsCollectionFromEntitySet <Product>("Products");

            var funcConfig = builder
                             .EntityType <Product>()
                             .Function("RelatedProducts")
                             .SetBindingParameter("product", builder.GetTypeConfigurationOrNull(typeof(Product)))
                             //.AddParameter("start", new PrimitiveTypeConfiguration(builder, builder.GetTypeConfigurationOrNull(typeof(DateTimeOffset)), typeof(DateTimeOffset)).
                             .ReturnsCollectionFromEntitySet <Product>("Products");

            funcConfig
            .Parameter <DateTimeOffset>("start");

            funcConfig
            .Parameter <DateTimeOffset>("end");

            //builder.Function("GetSalesTaxRate")
            //    .Returns<double>()
            //    .Parameter<int>("PostalCode");

            builder.EntitySet <Account>("Accounts");

            builder.EntityType <PaymentInstrument>()
            .Collection
            .Function("GetCount")
            .Returns <int>()
            .Parameter <string>("NameContains");

            var model = builder.GetEdmModel();

            var conventions = ODataRoutingConventions.CreateDefault();

            conventions.Insert(0, new AttributeRoutingConvention(model, httpConfiguration));

            var server = new BatchServer(httpConfiguration);

            httpConfiguration.MapODataServiceRoute(
                routeName: "ODataRoute",
                routePrefix: null,
                model: model,
                pathHandler: new DefaultODataPathHandler(),
                routingConventions: conventions,
                batchHandler: new DefaultODataBatchHandler(server));

            httpConfiguration.MessageHandlers.Add(new TracingMessageHandler());
        }
        private static void MapODataControllerActions(ODataConventionModelBuilder builder, Type ctrlType, EntityTypeConfiguration entityTypeConfig, EntitySetConfiguration entitySetConfig)
        {
            // Map actions
            var methods = ctrlType.GetMethods().Where(m => m.GetCustomAttribute <ODataProcedureAttribute>() != null);

            foreach (var method in methods)
            {
                var attr = method.GetCustomAttribute <ODataProcedureAttribute>();
                ProcedureConfiguration procedure;

                // TODO: Extract into separate class if possible
                Func <string, IEdmTypeConfiguration, ProcedureConfiguration> setBindingParameterFunc;

                string previousNamespace = builder.Namespace;
                builder.Namespace = attr.Namespace;

                if (attr.Type == ODataProcedureType.Action)
                {
                    // Create an action
                    procedure = builder.Action(attr.ProcedureName ?? method.Name);
                    setBindingParameterFunc = ((ActionConfiguration)procedure).SetBindingParameter;
                }
                else
                {
                    // Create a function
                    procedure = builder.Function(attr.ProcedureName ?? method.Name);
                    setBindingParameterFunc = ((FunctionConfiguration)procedure).SetBindingParameter;
                }

                builder.Namespace = previousNamespace;

                if (attr.Target == ODataProcedureTarget.Entity)
                {
                    // Bind to entity
                    setBindingParameterFunc(BindingParameterConfiguration.DefaultBindingParameterName, entityTypeConfig);
                }
                else
                {
                    // Bind to collection
                    var entityCollectionConfig = new CollectionTypeConfiguration(entityTypeConfig, typeof(Enumerable));
                    setBindingParameterFunc(BindingParameterConfiguration.DefaultBindingParameterName, entityCollectionConfig);
                }

                var parameterAttrs = method.GetCustomAttributes <ODataProcedureParameterAttribute>();
                foreach (var parameterAttr in parameterAttrs)
                {
                    var parameterType = parameterAttr.Type;

                    // Is the parameter type a collection?
                    if (parameterType.IsGenericType && parameterType.GetInterface(typeof(IEnumerable).Name, false) != null)
                    {
                        // If the parameter is a collection, we need to call the generic CollectionParameter<T>(name) method
                        var genericArgument = parameterType.GetGenericArguments().Single();

                        var parameterMethod = procedure.GetType().GetMethod("CollectionParameter");
                        var methodInfo      = parameterMethod.MakeGenericMethod(genericArgument);
                        methodInfo.Invoke(procedure, new object[] { parameterAttr.Name });
                    }
                    else
                    {
                        // If the parameter is not a collection, we call the generic Parameter<T>(name) method
                        var parameterMethod = procedure.GetType().GetMethod("Parameter");
                        var methodInfo      = parameterMethod.MakeGenericMethod(parameterType);
                        methodInfo.Invoke(procedure, new object[] { parameterAttr.Name });
                    }
                }

                if (attr.Returns != null)
                {
                    var returns = procedure.GetType().GetMethod("Returns");
                    var generic = returns.MakeGenericMethod(attr.Returns);
                    generic.Invoke(procedure, null);
                }
                else if (attr.ReturnsCollection != null)
                {
                    var returnsCollection = procedure.GetType().GetMethod("ReturnsCollection");
                    var generic           = returnsCollection.MakeGenericMethod(attr.ReturnsCollection);
                    generic.Invoke(procedure, null);
                }
                else if (attr.ReturnsEntity != null)
                {
                    var returnsEntity = procedure.GetType().GetMethod("ReturnsFromEntitySet", new Type[] { typeof(string) });
                    var generic       = returnsEntity.MakeGenericMethod(attr.ReturnsEntity);

                    var entitySet = builder.EntitySets.Single(set => set.ClrType == attr.ReturnsEntity);
                    generic.Invoke(procedure, new object[] { entitySet.Name });
                }
                else if (attr.ReturnsEntityCollection != null)
                {
                    var returnsEntity = procedure.GetType().GetMethod("ReturnsCollectionFromEntitySet", new Type[] { typeof(string) });
                    var generic       = returnsEntity.MakeGenericMethod(attr.ReturnsEntityCollection);

                    var entitySet = builder.EntitySets.Single(set => set.ClrType == attr.ReturnsEntityCollection);
                    generic.Invoke(procedure, new object[] { entitySet.Name });
                }
                else
                {
                    procedure.ReturnType = builder.GetTypeConfigurationOrNull(method.ReturnType);
                }
            }
        }
        /// <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;
        }