public void NonGenericEnumerableReturnType_ReturnsBadRequest()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            HttpRequestMessage   request   = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Customer/?$skip=1");
            HttpConfiguration    config    = new HttpConfiguration();

            config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
            request.SetConfiguration(config);
            HttpControllerContext     controllerContext    = new HttpControllerContext(config, new HttpRouteData(new HttpRoute()), request);
            HttpControllerDescriptor  controllerDescriptor = new HttpControllerDescriptor(new HttpConfiguration(), "CustomerHighLevel", typeof(CustomerHighLevelController));
            HttpActionDescriptor      actionDescriptor     = new ReflectedHttpActionDescriptor(controllerDescriptor, typeof(CustomerHighLevelController).GetMethod("GetNonGenericEnumerable"));
            HttpActionContext         actionContext        = new HttpActionContext(controllerContext, actionDescriptor);
            HttpActionExecutedContext context = new HttpActionExecutedContext(actionContext, null);

            context.Response         = new HttpResponseMessage(HttpStatusCode.OK);
            context.Response.Content = new ObjectContent(typeof(IEnumerable), new NonGenericEnumerable(), new JsonMediaTypeFormatter());

            // Act
            attribute.OnActionExecuted(context);
            string responseString = context.Response.Content.ReadAsStringAsync().Result;

            // Assert
            Assert.Equal(HttpStatusCode.BadRequest, context.Response.StatusCode);
            Assert.Contains("The query specified in the URI is not valid. Cannot create an EDM model as the action 'EnableQueryAttribute' " +
                            "on controller 'GetNonGenericEnumerable' has a return type 'CustomerHighLevel' that does not implement IEnumerable<T>.",
                            responseString);
        }
        public void SingleOrDefault_DisposeCalled_OneElementInSequence()
        {
            // Arrange
            var enumerator = new Mock <IEnumerator>(MockBehavior.Strict);

            enumerator.SetupSequence(mock => mock.MoveNext()).Returns(true).Returns(false);
            enumerator.SetupGet(mock => mock.Current).Returns(new Customer());

            var disposable = enumerator.As <IDisposable>();

            disposable.Setup(mock => mock.Dispose()).Verifiable();

            var queryable = new Mock <IQueryable>(MockBehavior.Strict);

            queryable.Setup(mock => mock.GetEnumerator()).Returns(enumerator.Object);

            var actionDescriptor = new ReflectedHttpActionDescriptor
            {
                Configuration        = new HttpConfiguration(),
                MethodInfo           = GetType().GetMethod("SomeAction", BindingFlags.Instance | BindingFlags.NonPublic),
                ControllerDescriptor = new HttpControllerDescriptor {
                    ControllerName = "SomeName"
                }
            };

            // Act
            EnableQueryAttribute.SingleOrDefault(queryable.Object, actionDescriptor);

            // Assert
            disposable.Verify();
        }
        public void Primitives_Can_Be_Used_For_Top_And_Skip(string filter)
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            HttpRequestMessage   request   = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Primitive/?" + filter);
            HttpConfiguration    config    = new HttpConfiguration();

            request.SetConfiguration(config);
            HttpControllerContext     controllerContext    = new HttpControllerContext(config, new HttpRouteData(new HttpRoute()), request);
            HttpControllerDescriptor  controllerDescriptor = new HttpControllerDescriptor(new HttpConfiguration(), "Primitive", typeof(PrimitiveController));
            HttpActionDescriptor      actionDescriptor     = new ReflectedHttpActionDescriptor(controllerDescriptor, typeof(PrimitiveController).GetMethod("GetIEnumerableOfInt"));
            HttpActionContext         actionContext        = new HttpActionContext(controllerContext, actionDescriptor);
            HttpActionExecutedContext context = new HttpActionExecutedContext(actionContext, null);

            context.Response = new HttpResponseMessage(HttpStatusCode.OK);
            HttpContent expectedResponse = new ObjectContent(typeof(IEnumerable <int>), new List <int>(), new JsonMediaTypeFormatter());

            context.Response.Content = expectedResponse;

            // Act and Assert
            attribute.OnActionExecuted(context);
            HttpResponseMessage response = context.Response;

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal(expectedResponse, response.Content);
        }
        public void NullContentResponse_DoesNotThrow()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            HttpRequestMessage   request   = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Customer?$skip=1");
            HttpConfiguration    config    = new HttpConfiguration();

            request.SetConfiguration(config);
            HttpControllerContext controllerContext = new HttpControllerContext(
                config,
                new HttpRouteData(new HttpRoute()),
                request);
            HttpControllerDescriptor controllerDescriptor = new HttpControllerDescriptor(
                new HttpConfiguration(),
                "CustomerHighLevel",
                typeof(CustomerHighLevelController));
            HttpActionDescriptor actionDescriptor = new ReflectedHttpActionDescriptor(
                controllerDescriptor,
                typeof(CustomerHighLevelController).GetMethod("GetIEnumerableOfCustomer"));
            HttpActionContext         actionContext = new HttpActionContext(controllerContext, actionDescriptor);
            HttpActionExecutedContext context       = new HttpActionExecutedContext(actionContext, null)
            {
                Response = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = null
                }
            };

            // Act & Assert
            Assert.DoesNotThrow(() => attribute.OnActionExecuted(context));
        }
 public ODataBinding(ODataContext context, EnableQueryAttribute attribute, Type type)
 {
     _context        = context ?? throw new ArgumentNullException(nameof(context));
     _attribute      = attribute ?? throw new ArgumentNullException(nameof(attribute));
     _type           = type ?? throw new ArgumentNullException(nameof(type));
     _optionsBuilder = BuildODataQueryOptionsFactory(_type);
 }
        public virtual void QueryableUsesConfiguredAssembliesResolver_For_MappingDerivedTypes()
        {
            // Arrange
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext(
                "http://localhost:8080/QueryCompositionCustomer/?$filter=Id eq 2",
                QueryCompositionCustomerController.CustomerList.AsQueryable());

            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();

            modelBuilder.EntitySet <QueryCompositionCustomer>(typeof(QueryCompositionCustomer).Name);
            IEdmModel model = modelBuilder.GetEdmModel();

            model.SetAnnotationValue <ClrTypeAnnotation>(model.FindType("System.Web.Http.OData.Query.QueryCompositionCustomer"), null);

            bool called = false;
            Mock <IAssembliesResolver> assembliesResolver = new Mock <IAssembliesResolver>();

            assembliesResolver
            .Setup(r => r.GetAssemblies())
            .Returns(new DefaultAssembliesResolver().GetAssemblies())
            .Callback(() => { called = true; })
            .Verifiable();
            actionExecutedContext.Request.GetConfiguration().Services.Replace(typeof(IAssembliesResolver), assembliesResolver.Object);

            // Act
            attribute.OnActionExecuted(actionExecutedContext);

            // Assert
            Assert.True(called);
        }
        public void ApplyQuery_Throws_WithNullQueryOptions()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();

            // Act & Assert
            Assert.ThrowsArgumentNull(() => attribute.ApplyQuery(CustomerList.AsQueryable(), null), "queryOptions");
        }
        public void ValidateQuery_Throws_WithNullQueryOptions()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();

            // Act & Assert
            Assert.ThrowsArgumentNull(() => attribute.ValidateQuery(new HttpRequestMessage(), null), "queryOptions");
        }
        public void ApplyQuery_SingleEntity_ThrowsArgumentNull_QueryOptions()
        {
            EnableQueryAttribute attribute = new EnableQueryAttribute();

            Assert.ThrowsArgumentNull(
                () => attribute.ApplyQuery(entity: 42, queryOptions: null),
                "queryOptions");
        }
Example #10
0
        public void RunQueryableOnAllPossibleTypes(Type type, string queryString)
        {
            int    seed           = RandomSeedGenerator.GetRandomSeed();
            Random r              = new Random(seed);
            Type   generic        = typeof(IEnumerable <>);
            var    collectionType = generic.MakeGenericType(type);

            Type listType = typeof(List <>).MakeGenericType(type);
            var  array    = Activator.CreateInstance(listType);

            EnableQueryAttribute q = new EnableQueryAttribute();
            var configuration      = new HttpConfiguration();

            configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
            configuration.Count().Filter().OrderBy().Expand().MaxTop(null).Select();
            configuration.Routes.MapHttpRoute("ApiDefault", "api/{controller}/{id}", new { id = RouteParameter.Optional });
            configuration.EnableDependencyInjection();
            var request = new HttpRequestMessage(HttpMethod.Get, "http://test/api/Objects?" + queryString);

            request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, configuration);
            var controllerContext = new HttpControllerContext(
                configuration,
                configuration.Routes.GetRouteData(request),
                request);
            var actionContext = new HttpActionContext(controllerContext, new ReflectedHttpActionDescriptor()
            {
                Configuration = configuration
            });
            var context = new HttpActionExecutedContext(actionContext, null);

            context.Response         = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
            context.Response.Content = new ObjectContent(collectionType, array, new JsonMediaTypeFormatter());

            try
            {
                q.OnActionExecuted(context);

                Console.WriteLine(context.Response.Content.ReadAsStringAsync().Result);
                Assert.Equal(HttpStatusCode.OK, context.Response.StatusCode);
            }
            catch (ArgumentException ae)
            {
                // For example:
                // The type 'System.DateTime' of property 'NotAfter' in the
                // 'System.Security.Cryptography.X509Certificates.X509Certificate2' type is not a supported type.
                // Change to use 'System.DateTimeOffset' or ignore this type by calling
                // Ignore<System.Security.Cryptography.X509Certificates.X509Certificate2>()
                // on 'System.Web.OData.Builder.ODataModelBuilder'.
                Assert.True(ae.Message.Contains("The type 'System.DateTime' of property") ||
                            ae.Message.Contains("System.Windows.Forms.AxHost") ||
                            ae.Message.Contains("Found more than one dynamic property container in type"),

                            "The exception should contains \"The type 'System.DateTime' of property\", or " +
                            "\"System.Windows.Forms.AxHost\" or" +
                            "\"Found more than one dynamic property container in type\", but actually, it is:" +
                            ae.Message);
            }
        }
        public void Ctor_Initializes_Properties()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();

            // Act & Assert
            Assert.Equal(HandleNullPropagationOption.Default, attribute.HandleNullPropagation);
            Assert.True(attribute.EnsureStableOrdering);
        }
        public void SingleOrDefault_IQueryableOfT_ZeroElementsInSequence_ReturnsNull()
        {
            IQueryable <Customer> queryable        = Enumerable.Empty <Customer>().AsQueryable();
            HttpActionDescriptor  actionDescriptor = new Mock <HttpActionDescriptor>().Object;

            var result = EnableQueryAttribute.SingleOrDefault(queryable, actionDescriptor);

            Assert.Null(result);
        }
        public void ApplyQuery_SingleEntity_ThrowsArgumentNull_Entity()
        {
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            ODataQueryOptions    options   = new ODataQueryOptions(new ODataQueryContext(EdmCoreModel.Instance, typeof(int)), new HttpRequestMessage());

            Assert.ThrowsArgumentNull(
                () => attribute.ApplyQuery(entity: null, queryOptions: options),
                "entity");
        }
        public void OnActionExecuted_SingleResult_Returns400_IfQueryContainsNonSelectExpand()
        {
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext("http://localhost/?$top=10", new Customer());
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();

            attribute.OnActionExecuted(actionExecutedContext);

            Assert.Equal(HttpStatusCode.BadRequest, actionExecutedContext.Response.StatusCode);
        }
        public void OrderByAllowedPropertiesWithSpaces(string allowedProperties)
        {
            EnableQueryAttribute attribute = new EnableQueryAttribute();

            attribute.AllowedOrderByProperties = allowedProperties;
            HttpRequestMessage request      = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Customers/?$orderby=Id,Name");
            ODataQueryOptions  queryOptions = new ODataQueryOptions(ValidationTestHelper.CreateCustomerContext(), request);

            Assert.DoesNotThrow(() => attribute.ValidateQuery(request, queryOptions));
        }
        public void ApplyQuery_Throws_With_Null_Queryable()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            var model   = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(System.Web.Http.OData.Builder.TestModels.Customer)), new HttpRequestMessage());

            // Act & Assert
            Assert.ThrowsArgumentNull(() => attribute.ApplyQuery(null, options), "queryable");
        }
        public void SingleOrDefault_IQueryableOfT_OneElementInSequence_ReturnsElement()
        {
            Customer customer = new Customer();
            IQueryable <Customer> queryable = new[] { customer }.AsQueryable();
            HttpActionDescriptor  actionDescriptor = new Mock <HttpActionDescriptor>().Object;

            var result = EnableQueryAttribute.SingleOrDefault(queryable, actionDescriptor);

            Assert.Same(customer, result);
        }
        public void OrderByDisllowedPropertiesWithSpaces(string allowedProperties)
        {
            EnableQueryAttribute attribute = new EnableQueryAttribute();

            attribute.AllowedOrderByProperties = allowedProperties;
            HttpRequestMessage request      = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Customers/?$orderby=Id,Name");
            ODataQueryOptions  queryOptions = new ODataQueryOptions(ValidationTestHelper.CreateCustomerContext(), request);

            Assert.Throws <ODataException>(() => attribute.ValidateQuery(request, queryOptions),
                                           "Order by 'Name' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings.");
        }
        public void ApplyQuery_Accepts_All_Supported_QueryNames(string query)
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            HttpRequestMessage   request   = new HttpRequestMessage(HttpMethod.Get, "http://localhost/?" + query);
            var model   = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(System.Web.Http.OData.Builder.TestModels.Customer)), request);

            // Act & Assert
            Assert.DoesNotThrow(() => attribute.ApplyQuery(new List <System.Web.Http.OData.Builder.TestModels.Customer>().AsQueryable(), options));
        }
        public void OnActionExecuted_SingleResult_WithMoreThanASingleQueryResult_ThrowsInvalidOperationException()
        {
            // Arrange
            var          customers = CustomerList.AsQueryable();
            SingleResult result    = SingleResult.Create(customers);
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext("http://localhost/", result);
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();

            // Act and Assert
            Assert.Throws <InvalidOperationException>(() => attribute.OnActionExecuted(actionExecutedContext));
        }
        public void ApplyQuery_CallsApplyOnODataQueryOptions()
        {
            object entity = new object();
            EnableQueryAttribute     attribute    = new EnableQueryAttribute();
            ODataQueryContext        context      = new ODataQueryContext(EdmCoreModel.Instance, typeof(int));
            HttpRequestMessage       request      = new HttpRequestMessage();
            Mock <ODataQueryOptions> queryOptions = new Mock <ODataQueryOptions>(context, request);

            attribute.ApplyQuery(entity, queryOptions.Object);

            queryOptions.Verify(q => q.ApplyTo(entity, It.IsAny <ODataQuerySettings>()), Times.Once());
        }
        public void QueryableOnActionUnknownOperatorStartingDollarSignThrows()
        {
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext(
                "http://localhost:8080/QueryCompositionCustomer?$orderby=Name desc&$unknown=12",
                QueryCompositionCustomerController.CustomerList.AsQueryable());

            var exception = Assert.Throws <HttpResponseException>(() => attribute.OnActionExecuted(actionExecutedContext));

            // EnableQueryAttribute will validate and throws
            Assert.Equal(HttpStatusCode.BadRequest, exception.Response.StatusCode);
        }
        public void GetFilters_ReturnsQueryableFilter_ForQueryableActions(string actionName)
        {
            var config = RoutingConfigurationFactory.Create();
            HttpControllerDescriptor controllerDescriptor = new HttpControllerDescriptor(config, "FilterProviderTest", typeof(FilterProviderTestController));
            HttpActionDescriptor     actionDescriptor     = new ReflectedHttpActionDescriptor(controllerDescriptor, typeof(FilterProviderTestController).GetMethod(actionName));

            FilterInfo[] filters = new QueryFilterProvider(new EnableQueryAttribute()).GetFilters(config, actionDescriptor).ToArray();

            Assert.Single(filters);
            Assert.Equal(FilterScope.Global, filters[0].Scope);
            EnableQueryAttribute filter = Assert.IsType <EnableQueryAttribute>(filters[0].Instance);
        }
        public void OnActionExecuted_SingleResult_ReturnsSingleItemEvenIfThereIsNoSelectExpand()
        {
            Customer     customer     = new Customer();
            SingleResult singleResult = new SingleResult <Customer>(new Customer[] { customer }.AsQueryable());
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext("http://localhost/", singleResult);
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();

            attribute.OnActionExecuted(actionExecutedContext);

            Assert.Equal(HttpStatusCode.OK, actionExecutedContext.Response.StatusCode);
            Assert.Equal(customer, (actionExecutedContext.Response.Content as ObjectContent).Value);
        }
        public void ValidateSelectExpandOnly_ThrowsODataException_IfODataQueryOptionsHasNonSelectExpand(string parameter)
        {
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();

            model.Model.SetAnnotationValue(model.Customer, new ClrTypeAnnotation(typeof(Customer)));
            HttpRequestMessage request      = new HttpRequestMessage(HttpMethod.Get, "http://localhost?" + parameter);
            ODataQueryContext  context      = new ODataQueryContext(model.Model, typeof(Customer));
            ODataQueryOptions  queryOptions = new ODataQueryOptions(context, request);

            Assert.Throws <ODataException>(
                () => EnableQueryAttribute.ValidateSelectExpandOnly(queryOptions),
                "The requested resource is not a collection. Query options $filter, $orderby, $inlinecount, $skip, and $top can be applied only on collections.");
        }
        public void QueryableOnActionUnknownOperatorIsAllowed()
        {
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext(
                "http://localhost:8080/?$orderby=$it desc&unknown=12",
                Enumerable.Range(0, 5).AsQueryable());

            // unsupported operator - ignored
            attribute.OnActionExecuted(actionExecutedContext);

            List <int> result = actionExecutedContext.Response.Content.ReadAsAsync <List <int> >().Result;

            Assert.Equal(new[] { 4, 3, 2, 1, 0 }, result);
        }
        public void OnActionExecuted_SingleResult_WithEmptyQueryResult_SetsNotFoundResponse()
        {
            // Arrange
            var          customers = Enumerable.Empty <Customer>().AsQueryable();
            SingleResult result    = SingleResult.Create(customers);
            HttpActionExecutedContext actionExecutedContext = GetActionExecutedContext("http://localhost/", result);
            EnableQueryAttribute      attribute             = new EnableQueryAttribute();

            // Act
            attribute.OnActionExecuted(actionExecutedContext);

            // Assert
            Assert.Equal(HttpStatusCode.NotFound, actionExecutedContext.Response.StatusCode);
        }
        public void ValidateQuery_Sends_BadRequest_For_Unrecognized_QueryNames()
        {
            // Arrange
            EnableQueryAttribute attribute = new EnableQueryAttribute();
            HttpRequestMessage   request   = new HttpRequestMessage(HttpMethod.Get, "http://localhost/?$xxx");
            var model   = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel();
            var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(System.Web.Http.OData.Builder.TestModels.Customer)), request);

            // Act & Assert
            HttpResponseException responseException = Assert.Throws <HttpResponseException>(
                () => attribute.ValidateQuery(request, options));

            Assert.Equal(HttpStatusCode.BadRequest, responseException.Response.StatusCode);
        }
        public void GetModel_ReturnsModel_ForNoModelOnRequest()
        {
            var entityClrType = typeof(QueryCompositionCustomer);
            var config        = new HttpConfiguration();
            var request       = new HttpRequestMessage(HttpMethod.Get, "http://localhost/");
            var descriptor    = new ReflectedHttpActionDescriptor();

            descriptor.Configuration = config;

            var queryModel = new EnableQueryAttribute().GetModel(entityClrType, request, descriptor);

            Assert.NotNull(queryModel);
            Assert.Same(descriptor.Properties["MS_EdmModelSystem.Web.Http.OData.Query.QueryCompositionCustomer"], queryModel);
        }
        public void SingleOrDefault_IQueryableOfT_MoreThaneOneElementInSequence_Throws()
        {
            IQueryable <Customer>         queryable = new[] { new Customer(), new Customer() }.AsQueryable();
            ReflectedHttpActionDescriptor actionDescriptor = new ReflectedHttpActionDescriptor
            {
                Configuration        = new HttpConfiguration(),
                MethodInfo           = GetType().GetMethod("SomeAction", BindingFlags.Instance | BindingFlags.NonPublic),
                ControllerDescriptor = new HttpControllerDescriptor {
                    ControllerName = "SomeName"
                }
            };

            Assert.Throws <InvalidOperationException>(
                () => EnableQueryAttribute.SingleOrDefault(queryable, actionDescriptor),
                "The action 'SomeAction' on controller 'SomeName' returned a SingleResult containing more than one element. " +
                "SingleResult must have zero or one elements.");
        }