public void CanCreateActionWithComplexReturnType() { // Arrange // Act ODataModelBuilder builder = new ODataModelBuilder(); ActionConfiguration createAddress = builder.Action("CreateAddress").Returns <Address>(); ActionConfiguration createAddresses = builder.Action("CreateAddresses").ReturnsCollection <Address>(); // Assert ComplexTypeConfiguration address = createAddress.ReturnType as ComplexTypeConfiguration; Assert.NotNull(address); Assert.Equal(typeof(Address).FullName, address.FullName); Assert.Null(createAddress.NavigationSource); CollectionTypeConfiguration addresses = createAddresses.ReturnType as CollectionTypeConfiguration; Assert.NotNull(addresses); Assert.Equal(string.Format("Collection({0})", typeof(Address).FullName), addresses.FullName); address = addresses.ElementType as ComplexTypeConfiguration; Assert.NotNull(address); Assert.Equal(typeof(Address).FullName, address.FullName); Assert.Null(createAddresses.NavigationSource); }
public void CanCreateFunctionWithEntityReturnType() { // Arrange & Act ODataModelBuilder builder = new ODataModelBuilder(); FunctionConfiguration createGoodCustomer = builder.Function("CreateGoodCustomer").ReturnsFromEntitySet <Customer>("GoodCustomers"); FunctionConfiguration createBadCustomers = builder.Function("CreateBadCustomers").ReturnsCollectionFromEntitySet <Customer>("BadCustomers"); // Assert EntityTypeConfiguration customer = createGoodCustomer.ReturnType as EntityTypeConfiguration; Assert.NotNull(customer); Assert.Equal(typeof(Customer).FullName, customer.FullName); EntitySetConfiguration goodCustomers = builder.EntitySets.SingleOrDefault(s => s.Name == "GoodCustomers"); Assert.NotNull(goodCustomers); Assert.Same(createGoodCustomer.NavigationSource, goodCustomers); CollectionTypeConfiguration customers = createBadCustomers.ReturnType as CollectionTypeConfiguration; Assert.NotNull(customers); customer = customers.ElementType as EntityTypeConfiguration; Assert.NotNull(customer); EntitySetConfiguration badCustomers = builder.EntitySets.SingleOrDefault(s => s.Name == "BadCustomers"); Assert.NotNull(badCustomers); Assert.Same(createBadCustomers.NavigationSource, badCustomers); }
private static IEdmTypeReference GetEdmTypeReference(Dictionary <Type, IEdmType> availableTypes, IEdmTypeConfiguration configuration, bool nullable) { Contract.Assert(availableTypes != null); if (configuration == null) { return(null); } EdmTypeKind kind = configuration.Kind; if (kind == EdmTypeKind.Collection) { CollectionTypeConfiguration collectionType = (CollectionTypeConfiguration)configuration; EdmCollectionType edmCollectionType = new EdmCollectionType(GetEdmTypeReference(availableTypes, collectionType.ElementType, nullable)); return(new EdmCollectionTypeReference(edmCollectionType)); } else { Type configurationClrType = TypeHelper.GetUnderlyingTypeOrSelf(configuration.ClrType); if (!TypeHelper.IsEnum(configurationClrType)) { configurationClrType = configuration.ClrType; } IEdmType type; if (availableTypes.TryGetValue(configurationClrType, out type)) { if (kind == EdmTypeKind.Complex) { return(new EdmComplexTypeReference((IEdmComplexType)type, nullable)); } else if (kind == EdmTypeKind.Entity) { return(new EdmEntityTypeReference((IEdmEntityType)type, nullable)); } else if (kind == EdmTypeKind.Enum) { return(new EdmEnumTypeReference((IEdmEnumType)type, nullable)); } else { throw Error.InvalidOperation(SRResources.UnsupportedEdmTypeKind, kind.ToString()); } } else if (configuration.Kind == EdmTypeKind.Primitive) { PrimitiveTypeConfiguration primitiveTypeConfiguration = (PrimitiveTypeConfiguration)configuration; EdmPrimitiveTypeKind typeKind = EdmTypeBuilder.GetTypeKind(primitiveTypeConfiguration.ClrType); return(EdmCoreModel.Instance.GetPrimitive(typeKind, nullable)); } else { throw Error.InvalidOperation(SRResources.NoMatchingIEdmTypeFound, configuration.FullName); } } }
private static void AddOperationLinkBuilder(IEdmModel model, IEdmOperation operation, OperationConfiguration operationConfiguration) { Contract.Assert(model != null); ActionConfiguration actionConfiguration = operationConfiguration as ActionConfiguration; IEdmAction action = operation as IEdmAction; FunctionConfiguration functionConfiguration = operationConfiguration as FunctionConfiguration; IEdmFunction function = operation as IEdmFunction; if (operationConfiguration.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Entity) { //if (actionConfiguration != null && actionConfiguration.GetActionLink() != null && action != null) //{ // model.SetOperationLinkBuilder( // action, // new OperationLinkBuilder(actionConfiguration.GetActionLink(), actionConfiguration.FollowsConventions)); //} //else if (functionConfiguration != null && functionConfiguration.GetFunctionLink() != null && function != null) //{ // model.SetOperationLinkBuilder( // function, // new OperationLinkBuilder(functionConfiguration.GetFunctionLink(), functionConfiguration.FollowsConventions)); //} } else if (operationConfiguration.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Collection) { CollectionTypeConfiguration collectionTypeConfiguration = (CollectionTypeConfiguration)operationConfiguration.BindingParameter.TypeConfiguration; if (collectionTypeConfiguration.ElementType.Kind == EdmTypeKind.Entity) { //if (actionConfiguration != null && actionConfiguration.GetFeedActionLink() != null && action != null) //{ // model.SetOperationLinkBuilder( // action, // new OperationLinkBuilder(actionConfiguration.GetFeedActionLink(), actionConfiguration.FollowsConventions)); //} //else if (functionConfiguration != null && functionConfiguration.GetFeedFunctionLink() != null && function != null) //{ // model.SetOperationLinkBuilder( // function, // new OperationLinkBuilder(functionConfiguration.GetFeedFunctionLink(), functionConfiguration.FollowsConventions)); //} } } }
private static void AddParameter( ODataConventionModelBuilder builder, OperationConfiguration configuration, Type pType, string name) { if (pType.IsPrimitiveType()) { var primitiveType = builder.AddPrimitiveType(pType); configuration.AddParameter(name, primitiveType); } else { if (pType.IsCollection()) { if (pType.GenericTypeArguments[0].GetTypeInfo() .IsPrimitive) { var parameterType = builder.AddPrimitiveType( pType.GenericTypeArguments[0]); var collectionTypeConfig = new CollectionTypeConfiguration( parameterType, pType.GenericTypeArguments[0]); configuration.AddParameter(name, collectionTypeConfig); } else { var parameterType = builder.AddEntityType( pType.GenericTypeArguments[0]); var collectionTypeConfig = new CollectionTypeConfiguration( parameterType, pType.GenericTypeArguments[0]); configuration.AddParameter(name, collectionTypeConfig); } } else { var parameterType = builder.AddEntityType(pType); configuration.AddParameter(name, parameterType); } } }
public void NonbindingParameterConfigurationSupportsParameterCollectionTypeAs(Type type, bool isNullable) { // Arrange ODataModelBuilder builder = new ODataModelBuilder(); builder.EntityType <Customer>(); builder.ComplexType <Address>(); builder.EnumType <Color>(); Type elementType; Assert.True(TypeHelper.IsCollection(type, out elementType)); // Act Type underlyingType = TypeHelper.GetUnderlyingTypeOrSelf(elementType); IEdmTypeConfiguration elementTypeConfiguration = builder.GetTypeConfigurationOrNull(underlyingType); CollectionTypeConfiguration collectionType = new CollectionTypeConfiguration(elementTypeConfiguration, typeof(IEnumerable <>).MakeGenericType(elementType)); NonbindingParameterConfiguration parameter = new NonbindingParameterConfiguration("name", collectionType); // Assert Assert.Equal(isNullable, parameter.Nullable); }
public static IEdmModel BuildEdmModel(Type ApiContextType) { ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.Namespace = ApiContextType.Namespace; var publicProperties = ApiContextType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in publicProperties) { var entityClrType = TypeHelper.GetImplementedIEnumerableType(property.PropertyType); EntityTypeConfiguration entity = builder.AddEntityType(entityClrType); builder.AddEntitySet(property.Name, entity); } // Get the actions and functions into the model var publicMethods = ApiContextType.GetMethods(BindingFlags.Public | BindingFlags.Instance); foreach (var method in publicMethods) { if (!method.IsSpecialName) { var entityClrType = TypeHelper.GetImplementedIEnumerableType(method.ReturnType) ?? method.ReturnType; OperationConfiguration configuration = null; PrimitiveTypeConfiguration primitiveEntityType = null; EntityTypeConfiguration entityType = null; if (entityClrType.GetTypeInfo().IsPrimitive || entityClrType.GetType() == typeof(decimal) || entityClrType.GetType() == typeof(string)) { primitiveEntityType = builder.AddPrimitiveType(entityClrType); } else { entityType = builder.AddEntityType(entityClrType); } var functionAttribute = method.GetCustomAttribute <ODataFunctionAttribute>(); if (functionAttribute != null) { configuration = builder.Function(method.Name); if (functionAttribute.IsBound) { configuration.SetBindingParameterImplementation(functionAttribute.BindingName, entityType); } } var actionAttribute = method.GetCustomAttribute <ODataActionAttribute>(); if (actionAttribute != null) { configuration = builder.Action(method.Name); if (actionAttribute.IsBound) { configuration.SetBindingParameterImplementation(actionAttribute.BindingName, entityType); } } if (configuration != null) { if (primitiveEntityType == null) { configuration.ReturnType = entityType; } else { configuration.ReturnType = primitiveEntityType; } configuration.IsComposable = true; configuration.NavigationSource = builder.NavigationSources.FirstOrDefault(n => n.EntityType == entityType) as NavigationSourceConfiguration; foreach (var parameterInfo in method.GetParameters()) { if (parameterInfo.ParameterType.GetTypeInfo().IsPrimitive || parameterInfo.ParameterType == typeof(decimal) || parameterInfo.ParameterType == typeof(string)) { var primitiveType = builder.AddPrimitiveType(parameterInfo.ParameterType); configuration.AddParameter(parameterInfo.Name, primitiveType); } else { if (parameterInfo.ParameterType.IsCollection()) { if (parameterInfo.ParameterType.GenericTypeArguments[0].GetTypeInfo().IsPrimitive) { var parameterType = builder.AddPrimitiveType(parameterInfo.ParameterType.GenericTypeArguments[0]); var collectionTypeConfig = new CollectionTypeConfiguration(parameterType, parameterInfo.ParameterType.GenericTypeArguments[0]); configuration.AddParameter(parameterInfo.Name, collectionTypeConfig); } else { var parameterType = builder.AddEntityType(parameterInfo.ParameterType.GenericTypeArguments[0]); var collectionTypeConfig = new CollectionTypeConfiguration(parameterType, parameterInfo.ParameterType.GenericTypeArguments[0]); configuration.AddParameter(parameterInfo.Name, collectionTypeConfig); } } else { var parameterType = builder.AddEntityType(parameterInfo.ParameterType); configuration.AddParameter(parameterInfo.Name, parameterType); } } } } } } return(builder.GetEdmModel()); }
public void CanBuildOperationBoundToCollectionCacheForIEdmModel() { // Arrange ODataModelBuilder builder = new ODataModelBuilder(); EntityTypeConfiguration <Customer> customer = builder.EntitySet <Customer>("Customers").EntityType; customer.HasKey(c => c.ID); customer.Property(c => c.Name); customer.ComplexProperty(c => c.Address); EntityTypeConfiguration <Movie> movie = builder.EntitySet <Movie>("Movies").EntityType; movie.HasKey(m => m.ID); movie.HasKey(m => m.Name); EntityTypeConfiguration <Blockbuster> blockBuster = builder.EntityType <Blockbuster>().DerivesFrom <Movie>(); EntityTypeConfiguration movieConfiguration = builder.StructuralTypes.OfType <EntityTypeConfiguration>().Single(t => t.Name == "Movie"); // build actions that are bindable to the collection of entity customer.Collection.Action("CollectionCustomerActionInCache1"); customer.Collection.Action("CollectionCustomerActionInCache2"); movie.Collection.Action("CollectionMovieActionInCache3"); ActionConfiguration movieActionIncache4 = builder.Action("CollectionMovieActionInCache4"); CollectionTypeConfiguration collectionConfiguration = new CollectionTypeConfiguration(movieConfiguration, typeof(Movie)); movieActionIncache4.SetBindingParameter("bindingParameter", collectionConfiguration); blockBuster.Collection.Action("CollectionBlockbusterActionInCache5"); // build functions that are bindable to the collection of entity customer.Collection.Function("CollectionCustomerFunctionInCache1").Returns <int>(); customer.Collection.Function("CollectionCustomerFunctionInCache2").Returns <int>(); movie.Collection.Function("CollectionMovieFunctionInCache3").Returns <int>(); blockBuster.Collection.Function("CollectionBlockbusterFunctionInCache5").Returns <int>(); // build actions that are either: bindable to an entity, have no parameter, have only complex parameter customer.Action("CustomersActionNotInCache1"); customer.Function("CustomersFunctionNotInCache1").Returns <int>(); movie.Action("MoviesActionNotInCache2"); builder.Action("NoParametersNotInCache3"); ActionConfiguration addressParameterNotInCache4 = builder.Action("AddressParameterNotInCache4"); addressParameterNotInCache4.Parameter <Address>("address"); IEdmModel model = builder.GetEdmModel(); IEdmEntityType customerType = model.SchemaElements.OfType <IEdmEntityType>().Single(e => e.Name == "Customer"); IEdmEntityType movieType = model.SchemaElements.OfType <IEdmEntityType>().Single(e => e.Name == "Movie"); IEdmEntityType blockBusterType = model.SchemaElements.OfType <IEdmEntityType>().Single(e => e.Name == "Blockbuster"); // Act BindableOperationFinder annotation = new BindableOperationFinder(model); var movieOperations = annotation.FindOperationsBoundToCollection(movieType).ToArray(); var customerOperations = annotation.FindOperationsBoundToCollection(customerType).ToArray(); var blockBusterOperations = annotation.FindOperationsBoundToCollection(blockBusterType).ToArray(); // Assert Assert.Equal(3, movieOperations.Length); Assert.Single(movieOperations.Where(a => a.Name == "CollectionMovieActionInCache3")); Assert.Single(movieOperations.Where(a => a.Name == "CollectionMovieActionInCache4")); Assert.Single(movieOperations.Where(a => a.Name == "CollectionMovieFunctionInCache3")); Assert.Equal(4, customerOperations.Length); Assert.Single(customerOperations.Where(a => a.Name == "CollectionCustomerActionInCache1")); Assert.Single(customerOperations.Where(a => a.Name == "CollectionCustomerActionInCache2")); Assert.Single(customerOperations.Where(a => a.Name == "CollectionCustomerFunctionInCache1")); Assert.Single(customerOperations.Where(a => a.Name == "CollectionCustomerFunctionInCache2")); Assert.Equal(5, blockBusterOperations.Length); Assert.Single(blockBusterOperations.Where(a => a.Name == "CollectionBlockbusterActionInCache5")); Assert.Single(blockBusterOperations.Where(a => a.Name == "CollectionBlockbusterFunctionInCache5")); Assert.Single(blockBusterOperations.Where(a => a.Name == "CollectionMovieActionInCache3")); Assert.Single(blockBusterOperations.Where(a => a.Name == "CollectionMovieActionInCache4")); Assert.Single(blockBusterOperations.Where(a => a.Name == "CollectionMovieFunctionInCache3")); }
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); } } }