Esempio n. 1
0
        internal static IEdmModel GetEdmModel(this ApiActionDescriptor actionDescriptor, Type entityClrType)
        {
            if (actionDescriptor == null)
            {
                throw Error.ArgumentNull("actionDescriptor");
            }

            if (entityClrType == null)
            {
                throw Error.ArgumentNull("entityClrType");
            }

            // save the EdmModel to the action descriptor
            return actionDescriptor.Properties.GetOrAdd(EdmModelKey + entityClrType.FullName, _ =>
            {
                // It's safe to create HttpConfiguration, since it's used as an assembly Resolver.
                //ODataConventionModelBuilder builder = new ODataConventionModelBuilder(new HttpConfiguration(), isQueryCompositionMode: true);
                ODataConventionModelBuilder builder = new ODataConventionModelBuilder(new HttpConfiguration());
                EntityTypeConfiguration entityTypeConfiguration = builder.AddEntity(entityClrType);
                builder.AddEntitySet(entityClrType.Name, entityTypeConfiguration);
                IEdmModel edmModel = builder.GetEdmModel();
                Contract.Assert(edmModel != null);
                return edmModel;
            }) as IEdmModel;
        }
        internal static IEdmModel GetEdmModel(this HttpActionDescriptor actionDescriptor, Type entityClrType)
        {
            if (actionDescriptor == null)
            {
                throw Error.ArgumentNull("actionDescriptor");
            }

            if (entityClrType == null)
            {
                throw Error.ArgumentNull("entityClrType");
            }

            // save the EdmModel to the action descriptor
            return actionDescriptor.Properties.GetOrAdd(EdmModelKey + entityClrType.FullName, _ =>
                    {
                        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
                        IEntityTypeConfiguration entityTypeConfiguration = builder.AddEntity(entityClrType);
                        builder.AddEntitySet(entityClrType.Name, entityTypeConfiguration);
                        return builder.GetEdmModel();
                    }) as IEdmModel;
        }
Esempio n. 3
0
        public void DollarMetadata_Works_WithPrincipalKeyOnBaseType_ButBaseTypeNotInEdmModel(Type entityType)
        {
            // Arrange
            const string expect =
                "      <Association Name=\"System_Web_Http_OData_Formatter_DependentEntity_DerivedProp_System_Web_Http_OData_Formatter_DerivedPrincipalEntity_DerivedPropPartner\">\r\n" +
                "        <End Type=\"System.Web.Http.OData.Formatter.DerivedPrincipalEntity\" Role=\"DerivedProp\" Multiplicity=\"0..1\" />\r\n" +
                "        <End Type=\"System.Web.Http.OData.Formatter.DependentEntity\" Role=\"DerivedPropPartner\" Multiplicity=\"0..1\" />\r\n" +
                "        <ReferentialConstraint>\r\n" +
                "          <Principal Role=\"DerivedProp\">\r\n" +
                "            <PropertyRef Name=\"Id\" />\r\n" +
                "          </Principal>\r\n" +
                "          <Dependent Role=\"DerivedPropPartner\">\r\n" +
                "            <PropertyRef Name=\"DerivedPrincipalEntityId\" />\r\n" +
                "          </Dependent>\r\n" +
                "        </ReferentialConstraint>\r\n" +
                "      </Association>";

            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

            builder.AddEntity(entityType);
            builder.Entity <DependentEntity>();
            IEdmModel model = builder.GetEdmModel();

            HttpServer server = new HttpServer();

            server.Configuration.Routes.MapODataServiceRoute("odata", "odata", model);

            HttpClient client = new HttpClient(server);

            // Act
            HttpResponseMessage response = client.GetAsync("http://localhost/odata/$metadata").Result;

            // Assert
            Assert.True(response.IsSuccessStatusCode);
            Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);

            Assert.Contains(expect, response.Content.ReadAsStringAsync().Result);
        }
Esempio n. 4
0
        public void GetEdmModel_PropertyWithDatabaseAttribute_ConfigAnnotationOnPropertyOnEntityType()
        {
            // Arrange
            MockType type =
                new MockType("Entity")
                .Property(typeof(int), "ID", new DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity))
                .Property(typeof(int?), "Count");

            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

            builder.AddEntity(type);

            // Act
            IEdmModel model = builder.GetEdmModel();

            // Assert
            IEdmEntityType         entity     = model.AssertHasEntityType(type);
            IEdmStructuralProperty idProperty = entity.AssertHasPrimitiveProperty(model, "ID",
                                                                                  EdmPrimitiveTypeKind.Int32, isNullable: false);

            var idAnnotation = model.GetAnnotationValue <EdmStringConstant>(
                idProperty,
                StoreGeneratedPatternAnnotation.AnnotationsNamespace,
                StoreGeneratedPatternAnnotation.AnnotationName);

            Assert.Equal(DatabaseGeneratedOption.Identity.ToString(), idAnnotation.Value);

            IEdmStructuralProperty countProperty = entity.AssertHasPrimitiveProperty(model, "Count",
                                                                                     EdmPrimitiveTypeKind.Int32, isNullable: true);

            var countAnnotation = model.GetAnnotationValue <EdmStringConstant>(
                countProperty,
                StoreGeneratedPatternAnnotation.AnnotationsNamespace,
                StoreGeneratedPatternAnnotation.AnnotationName);

            Assert.Null(countAnnotation);
        }
        internal static IEdmModel GetEdmModel(this HttpActionDescriptor actionDescriptor, Type entityClrType)
        {
            if (actionDescriptor == null)
            {
                throw Error.ArgumentNull("actionDescriptor");
            }

            if (entityClrType == null)
            {
                throw Error.ArgumentNull("entityClrType");
            }

            // save the EdmModel to the action descriptor
            return actionDescriptor.Properties.GetOrAdd(ModelKeyPrefix + entityClrType.FullName, _ =>
                {
                    ODataConventionModelBuilder builder =
                        new ODataConventionModelBuilder(actionDescriptor.Configuration, isQueryCompositionMode: true);
                    EntityTypeConfiguration entityTypeConfiguration = builder.AddEntity(entityClrType);
                    builder.AddEntitySet(entityClrType.Name, entityTypeConfiguration);
                    IEdmModel edmModel = builder.GetEdmModel();
                    Contract.Assert(edmModel != null);
                    return edmModel;
                }) as IEdmModel;
        }
        public void ApplyTo_Picks_DefaultOrder(string oDataQuery, Type elementType, string expectedExpression)
        {
            IQueryable query = Array.CreateInstance(elementType, 0).AsQueryable();
            var modelBuilder = new ODataConventionModelBuilder();
            modelBuilder.AddEntitySet("entityset", modelBuilder.AddEntity(elementType));
            var model = modelBuilder.GetEdmModel();

            var message = new HttpRequestMessage(
                HttpMethod.Get,
                new Uri("http://server/service/entityset?" + oDataQuery)
            );

            var options = new ODataQueryOptions(new ODataQueryContext(model, elementType, "entityset"), message);
            IQueryable finalQuery = options.ApplyTo(query);

            string queryExpression = finalQuery.Expression.ToString();
            queryExpression = queryExpression.Substring(queryExpression.IndexOf("OrderBy"));

            Assert.Equal(queryExpression, expectedExpression);
        }
        public void GetEdmModel_PropertyWithDatabaseAttribute_ConfigAnnotationOnPropertyOnEntityType()
        {
            // Arrange
            MockType type =
                new MockType("Entity")
                .Property(typeof(int), "ID", new DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity))
                .Property(typeof(int?), "Count");

            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.AddEntity(type);

            // Act
            IEdmModel model = builder.GetEdmModel();

            // Assert
            IEdmEntityType entity = model.AssertHasEntityType(type);
            IEdmStructuralProperty idProperty = entity.AssertHasPrimitiveProperty(model, "ID",
                EdmPrimitiveTypeKind.Int32, isNullable: false);

            var idAnnotation = model.GetAnnotationValue<EdmStringConstant>(
                idProperty,
                StoreGeneratedPatternAnnotation.AnnotationsNamespace,
                StoreGeneratedPatternAnnotation.AnnotationName);
            Assert.Equal(DatabaseGeneratedOption.Identity.ToString(), idAnnotation.Value);

            IEdmStructuralProperty countProperty = entity.AssertHasPrimitiveProperty(model, "Count",
                EdmPrimitiveTypeKind.Int32, isNullable: true);

            var countAnnotation = model.GetAnnotationValue<EdmStringConstant>(
                countProperty,
                StoreGeneratedPatternAnnotation.AnnotationsNamespace,
                StoreGeneratedPatternAnnotation.AnnotationName);
            Assert.Null(countAnnotation);
        }
Esempio n. 8
0
        /// <summary>
        /// Maps ODataService Route and registers routes for any controller actions that use a [Route] attribute
        /// </summary>
        /// <param name="config">The configuration.</param>
        public static void Register( HttpConfiguration config )
        {
            config.EnableCors( new Rock.Rest.EnableCorsFromOriginAttribute() );
            config.Filters.Add( new Rock.Rest.Filters.ValidateAttribute() );
            config.Services.Replace( typeof( IExceptionLogger ), new RockApiExceptionLogger() );
            config.Services.Replace( typeof( IExceptionHandler ), new RockApiExceptionHandler() );
            config.Formatters.Insert( 0, new Rock.Utility.RockJsonMediaTypeFormatter() );

            // Add API route for dataviews
            config.Routes.MapHttpRoute(
                name: "DataViewApi",
                routeTemplate: "api/{controller}/DataView/{id}",
                defaults: new
                {
                    action = "DataView"
                } );

            // finds all [Route] attributes on REST controllers and creates the routes 
            config.MapHttpAttributeRoutes();

            // Add any custom api routes
            foreach ( var type in Rock.Reflection.FindTypes(
                typeof( Rock.Rest.IHasCustomRoutes ) ) )
            {
                try
                {
                    var controller = (Rock.Rest.IHasCustomRoutes)Activator.CreateInstance( type.Value );
                    if ( controller != null )
                    {
                        controller.AddRoutes( RouteTable.Routes );
                    }
                }
                catch
                {
                    // ignore, and skip adding routes if the controller raises an exception
                }
            }

            //// Add Default API Service routes
            //// Instead of being able to use one default route that gets action from http method, have to 
            //// have a default route for each method so that other actions do not match the default (i.e. DataViews).
            //// Also, this will make controller routes case-insensitive (vs the odata routing)
            config.Routes.MapHttpRoute(
                name: "DefaultApiGetById",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    action = "GetById"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "GET", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiGetFunction",
                routeTemplate: "api/{controller}({key})",
                defaults: new
                {
                    action = "GET"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "GET", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiGetList",
                routeTemplate: "api/{controller}",
                defaults: new
                {
                    action = "GET"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "GET", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            config.Routes.MapHttpRoute(
               name: "DefaultApiPut",
               routeTemplate: "api/{controller}/{id}",
               defaults: new
               {
                   action = "PUT",
                   id = System.Web.Http.RouteParameter.Optional
               },
               constraints: new
               {
                   httpMethod = new HttpMethodConstraint( new string[] { "PUT", "OPTIONS" } ),
                   controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
               } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiPost",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    action = "POST",
                    id = System.Web.Http.RouteParameter.Optional,
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "POST", "OPTIONS" } )
                } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiDelete",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    action = "DELETE",
                    id = System.Web.Http.RouteParameter.Optional
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "DELETE", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            // build OData model and create service route (mainly for metadata)
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

            var entityTypeList = Reflection.FindTypes( typeof( Rock.Data.IEntity ) )
                .Where( a => !a.Value.IsAbstract && ( a.Value.GetCustomAttribute<NotMappedAttribute>() == null ) && (a.Value.GetCustomAttribute<DataContractAttribute>() != null) )
                .OrderBy( a => a.Key ).Select( a => a.Value );

            foreach ( var entityType in entityTypeList )
            {
                var entityTypeConfig = builder.AddEntity( entityType );
                var entitySetConfig = builder.AddEntitySet( entityType.Name.Pluralize(), entityTypeConfig );
            }

            config.Routes.MapODataServiceRoute( "api", "api", builder.GetEdmModel() );
        }
Esempio n. 9
0
        public static IEdmModel GetEdmModel(HttpConfiguration configuration)
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder(configuration);

            foreach (var type in Creator.EntityTypes)
            {
                var entity = builder.AddEntity(type);
                builder.AddEntitySet(type.Name, entity);
            }

            return builder.GetEdmModel();
        }
        public void DollarMetadata_Works_WithPrincipalKeyOnBaseType_ButBaseTypeNotInEdmModel(Type entityType)
        {
            // Arrange
            const string expect =
               "      <Association Name=\"System_Web_Http_OData_Formatter_DependentEntity_DerivedProp_System_Web_Http_OData_Formatter_DerivedPrincipalEntity_DerivedPropPartner\">\r\n" +
               "        <End Type=\"System.Web.Http.OData.Formatter.DerivedPrincipalEntity\" Role=\"DerivedProp\" Multiplicity=\"0..1\" />\r\n" +
               "        <End Type=\"System.Web.Http.OData.Formatter.DependentEntity\" Role=\"DerivedPropPartner\" Multiplicity=\"0..1\" />\r\n" +
               "        <ReferentialConstraint>\r\n" +
               "          <Principal Role=\"DerivedProp\">\r\n" +
               "            <PropertyRef Name=\"Id\" />\r\n" +
               "          </Principal>\r\n" +
               "          <Dependent Role=\"DerivedPropPartner\">\r\n" +
               "            <PropertyRef Name=\"DerivedPrincipalEntityId\" />\r\n" +
               "          </Dependent>\r\n" +
               "        </ReferentialConstraint>\r\n" +
               "      </Association>";

            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.AddEntity(entityType);
            builder.Entity<DependentEntity>();
            IEdmModel model = builder.GetEdmModel();

            HttpServer server = new HttpServer();
            server.Configuration.Routes.MapODataServiceRoute("odata", "odata", model);

            HttpClient client = new HttpClient(server);

            // Act
            HttpResponseMessage response = client.GetAsync("http://localhost/odata/$metadata").Result;

            // Assert
            Assert.True(response.IsSuccessStatusCode);
            Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);

            Assert.Contains(expect, response.Content.ReadAsStringAsync().Result);
        }
Esempio n. 11
0
        /// <summary>
        /// Maps ODataService Route and registers routes for any controller actions that use a [Route] attribute
        /// </summary>
        /// <param name="config">The configuration.</param>
        public static void Register( HttpConfiguration config )
        {
            config.EnableCors( new Rock.Rest.EnableCorsFromOriginAttribute() );
            config.Filters.Add( new Rock.Rest.Filters.ValidateAttribute() );
            config.Services.Replace( typeof( IExceptionLogger ), new RockApiExceptionLogger() );
            config.Services.Replace( typeof( IExceptionHandler ), new RockApiExceptionHandler() );
            config.Formatters.Insert( 0, new Rock.Utility.RockJsonMediaTypeFormatter() );

            // Change DateTimeZoneHandling to Unspecified instead of the default of RoundTripKind since Rock doesn't store dates in a timezone aware format
            // So, since Rock doesn't do TimeZones, we don't want Transmission of DateTimes to specify TimeZone either.
            config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Unspecified;

            // Add API route for dataviews
            config.Routes.MapHttpRoute(
                name: "DataViewApi",
                routeTemplate: "api/{controller}/DataView/{id}",
                defaults: new
                {
                    action = "DataView"
                } );

            // Add API route for Launching a Workflow
            config.Routes.MapHttpRoute(
                name: "LaunchWorkflowApi",
                routeTemplate: "api/{controller}/LaunchWorkflow/{id}",
                defaults: new
                {
                    action = "LaunchWorkflow"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "POST" } ),
                } );

            // Add API route for DeleteAttributeValue
            config.Routes.MapHttpRoute(
                name: "DeleteAttributeValueApi",
                routeTemplate: "api/{controller}/AttributeValue/{id}",
                defaults: new
                {
                    action = "DeleteAttributeValue"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "DELETE" } ),
                } );

            // Add API route for SetAttributeValue
            config.Routes.MapHttpRoute(
                name: "SetAttributeValueApi",
                routeTemplate: "api/{controller}/AttributeValue/{id}",
                defaults: new
                {
                    action = "SetAttributeValue"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "POST" } ),
                } );

            // Add API route for setting context
            config.Routes.MapHttpRoute(
                name: "SetContextApi",
                routeTemplate: "api/{controller}/SetContext/{id}",
                defaults: new
                {
                    action = "SetContext"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "PUT", "OPTIONS" } ),
                } );

            // finds all [Route] attributes on REST controllers and creates the routes
            config.MapHttpAttributeRoutes();

            // Add any custom api routes
            foreach ( var type in Rock.Reflection.FindTypes(
                typeof( Rock.Rest.IHasCustomRoutes ) ) )
            {
                try
                {
                    var controller = (Rock.Rest.IHasCustomRoutes)Activator.CreateInstance( type.Value );
                    if ( controller != null )
                    {
                        controller.AddRoutes( RouteTable.Routes );
                    }
                }
                catch
                {
                    // ignore, and skip adding routes if the controller raises an exception
                }
            }

            //// Add Default API Service routes
            //// Instead of being able to use one default route that gets action from http method, have to
            //// have a default route for each method so that other actions do not match the default (i.e. DataViews).
            //// Also, this will make controller routes case-insensitive (vs the odata routing)
            config.Routes.MapHttpRoute(
                name: "DefaultApiGetById",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    action = "GetById"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "GET", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiGetFunction",
                routeTemplate: "api/{controller}({key})",
                defaults: new
                {
                    action = "GET"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "GET", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiGetList",
                routeTemplate: "api/{controller}",
                defaults: new
                {
                    action = "GET"
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "GET", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            config.Routes.MapHttpRoute(
               name: "DefaultApiPut",
               routeTemplate: "api/{controller}/{id}",
               defaults: new
               {
                   action = "PUT",
                   id = System.Web.Http.RouteParameter.Optional
               },
               constraints: new
               {
                   httpMethod = new HttpMethodConstraint( new string[] { "PUT", "OPTIONS" } ),
                   controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
               } );

            config.Routes.MapHttpRoute(
               name: "DefaultApiPatch",
               routeTemplate: "api/{controller}/{id}",
               defaults: new
               {
                   action = "PATCH",
                   id = System.Web.Http.RouteParameter.Optional
               },
               constraints: new
               {
                   httpMethod = new HttpMethodConstraint( new string[] { "PATCH", "OPTIONS" } ),
                   controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
               } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiPost",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    action = "POST",
                    id = System.Web.Http.RouteParameter.Optional,
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "POST", "OPTIONS" } )
                } );

            config.Routes.MapHttpRoute(
                name: "DefaultApiDelete",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    action = "DELETE",
                    id = System.Web.Http.RouteParameter.Optional
                },
                constraints: new
                {
                    httpMethod = new HttpMethodConstraint( new string[] { "DELETE", "OPTIONS" } ),
                    controllerName = new Rock.Rest.Constraints.ValidControllerNameConstraint()
                } );

            // build OData model and create service route (mainly for metadata)
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

            var entityTypeList = Reflection.FindTypes( typeof( Rock.Data.IEntity ) )
                .Where( a => !a.Value.IsAbstract && ( a.Value.GetCustomAttribute<NotMappedAttribute>() == null ) && ( a.Value.GetCustomAttribute<DataContractAttribute>() != null ) )
                .OrderBy( a => a.Key ).Select( a => a.Value );

            foreach ( var entityType in entityTypeList )
            {
                var entityTypeConfig = builder.AddEntity( entityType );

                var tableAttribute = entityType.GetCustomAttribute<TableAttribute>();
                string name;
                if ( tableAttribute != null )
                {
                    name = tableAttribute.Name.Pluralize();
                }
                else
                {
                    name = entityType.Name.Pluralize();
                }

                var entitySetConfig = builder.AddEntitySet( name, entityTypeConfig );
            }

            config.Routes.MapODataServiceRoute( "api", "api", builder.GetEdmModel() );
        }