Exemplo n.º 1
0
        public void ApplyTo_NewQueryReturned_GivenQueryableAndIsIfNoneMatch()
        {
            // Arrange
            ETag <Customer> etagCustomer = new ETag <Customer> {
                IsIfNoneMatch = true
            };
            dynamic etag = etagCustomer;

            etag.LastName = "Xyz";

            // Act
            IQueryable queryable = etagCustomer.ApplyTo(_customers.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IEnumerable <Customer> actualCustomers = Assert.IsAssignableFrom <IEnumerable <Customer> >(queryable);

            Assert.Equal(
                new[] { 1 },
                actualCustomers.Select(customer => customer.ID));
            MethodCallExpression methodCall = queryable.Expression as MethodCallExpression;

            Assert.NotNull(methodCall);
            Assert.Equal(2, methodCall.Arguments.Count);
            Assert.Equal(
                @"Param_0 => Not((Param_0.LastName == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty))",
                methodCall.Arguments[1].ToString());
        }
Exemplo n.º 2
0
        public void ApplyTo_NewQueryReturned_IsIfNoneMatchWithMultipleConcurrencyProperties()
        {
            // Arrange
            ETag etagCustomer = new ETag {
                EntityType = typeof(Customer), IsIfNoneMatch = true
            };
            dynamic etag = etagCustomer;

            etag.FirstName = "Def";
            etag.LastName  = "Xyz";

            // Act
            IQueryable queryable = etagCustomer.ApplyTo(_customers.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IEnumerable <Customer> actualCustomers = Assert.IsAssignableFrom <IEnumerable <Customer> >(queryable);

            Assert.Equal(
                new[] { 1, 2 },
                actualCustomers.Select(customer => customer.ID));
            MethodCallExpression methodCall = queryable.Expression as MethodCallExpression;

            Assert.NotNull(methodCall);
            Assert.Equal(2, methodCall.Arguments.Count);
            Assert.Equal(
                @"Param_0 => Not(((Param_0.FirstName == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty) "
                + "AndAlso (Param_0.LastName == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty)))",
                methodCall.Arguments[1].ToString());
        }
Exemplo n.º 3
0
        public void ApplyTo_NewQueryReturned_GivenQueryable()
        {
            // Arrange
            ETag etagCustomer = new ETag {
                EntityType = typeof(ETagCustomer)
            };
            dynamic etag = etagCustomer;

            etag.FirstName = "Foo";

            // Act
            IQueryable queryable = etagCustomer.ApplyTo(_customers.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IEnumerable <ETagCustomer> actualCustomers = Assert.IsAssignableFrom <IEnumerable <ETagCustomer> >(queryable);

            Assert.Equal(
                new[] { 1 },
                actualCustomers.Select(customer => customer.ID));
            MethodCallExpression methodCall = queryable.Expression as MethodCallExpression;

            Assert.NotNull(methodCall);
            Assert.Equal(2, methodCall.Arguments.Count);
            Assert.Equal(@"Param_0 => (Param_0.FirstName == value(Microsoft.AspNetCore.OData.Query.Container.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty)",
                         methodCall.Arguments[1].ToString());
        }
Exemplo n.º 4
0
        public void ApplyToNonGenericThrows_IfPassedAnIQueryableOfTheWrongType()
        {
            // Arrange
            ETag <Customer> etagCustomer = new ETag <Customer> {
                IsIfNoneMatch = true
            };
            IQueryable query = Enumerable.Empty <int>().AsQueryable();

            // Act & Assert
#if NETCOREAPP3_0
            ExceptionAssert.Throws <ArgumentException>(
                () => etagCustomer.ApplyTo(query),
                "Cannot apply ETag of 'Microsoft.AspNet.OData.Test.Formatter.Serialization.Models.Customer' to IQueryable of " +
                "'System.Int32'. (Parameter 'query')");
#else
            ExceptionAssert.Throws <ArgumentException>(
                () => etagCustomer.ApplyTo(query),
                "Cannot apply ETag of 'Microsoft.AspNet.OData.Test.Formatter.Serialization.Models.Customer' to IQueryable of " +
                "'System.Int32'.\r\nParameter name: query");
#endif
        }
Exemplo n.º 5
0
        public void ApplyTo_SameQueryReturned_GivenQueryableAndETagAny()
        {
            // Arrange
            var any = new ETag {
                IsAny = true
            };
            var customers = _customers.AsQueryable();

            // Act
            var queryable = any.ApplyTo(customers);

            // Assert
            Assert.NotNull(queryable);
            Assert.Same(queryable, customers);
        }
Exemplo n.º 6
0
        private IReadOnlyDictionary <string, object> GetOriginalValues()
        {
            Dictionary <string, object> originalValues = new Dictionary <string, object>();

            EntityTagHeaderValue etagHeaderValue = this.Request.Headers.IfMatch.SingleOrDefault();

            if (etagHeaderValue != null)
            {
                ETag etag = this.Request.GetETag(etagHeaderValue);
                etag.ApplyTo(originalValues);

                originalValues.Add(ETagHeaderKey, etagHeaderValue.Tag);
            }

            return(originalValues);
        }
Exemplo n.º 7
0
        private async Task <IReadOnlyDictionary <string, object> > GetOriginalValues(IEdmEntitySet entitySet)
        {
            Dictionary <string, object> originalValues = new Dictionary <string, object>();

            EntityTagHeaderValue etagHeaderValue = this.Request.Headers.IfMatch.SingleOrDefault();

            if (etagHeaderValue != null)
            {
                ETag etag = this.Request.GetETag(etagHeaderValue);
                etag.ApplyTo(originalValues);

                originalValues.Add(IfMatchKey, etagHeaderValue.Tag);
                return(originalValues);
            }

            etagHeaderValue = this.Request.Headers.IfNoneMatch.SingleOrDefault();
            if (etagHeaderValue != null)
            {
                ETag etag = this.Request.GetETag(etagHeaderValue);
                etag.ApplyTo(originalValues);

                originalValues.Add(IfNoneMatchKey, etagHeaderValue.Tag);
                return(originalValues);
            }

            // return 428(Precondition Required) if entity requires concurrency check.
            var model = await this.Api.GetModelAsync();

            bool needEtag = model.IsConcurrencyCheckEnabled(entitySet);

            if (needEtag)
            {
                return(null);
            }

            return(originalValues);
        }
Exemplo n.º 8
0
        private HttpResponseMessage CreateQueryResponse(IQueryable query, IEdmType edmType, ETag etag)
        {
            var typeReference = GetTypeReference(edmType);
            BaseSingleResult    singleResult = null;
            HttpResponseMessage response     = null;

            if (typeReference.IsPrimitive())
            {
                if (shouldReturnCount || shouldWriteRawValue)
                {
                    var rawResult = new RawResult(query, typeReference);
                    singleResult = rawResult;
                    response     = Request.CreateResponse(HttpStatusCode.OK, rawResult);
                }
                else
                {
                    var primitiveResult = new PrimitiveResult(query, typeReference);
                    singleResult = primitiveResult;
                    response     = Request.CreateResponse(HttpStatusCode.OK, primitiveResult);
                }
            }

            if (typeReference.IsComplex())
            {
                var complexResult = new ComplexResult(query, typeReference);
                singleResult = complexResult;
                response     = Request.CreateResponse(HttpStatusCode.OK, complexResult);
            }

            if (typeReference.IsEnum())
            {
                if (shouldWriteRawValue)
                {
                    var rawResult = new RawResult(query, typeReference);
                    singleResult = rawResult;
                    response     = Request.CreateResponse(HttpStatusCode.OK, rawResult);
                }
                else
                {
                    var enumResult = new EnumResult(query, typeReference);
                    singleResult = enumResult;
                    response     = Request.CreateResponse(HttpStatusCode.OK, enumResult);
                }
            }

            if (singleResult != null)
            {
                if (singleResult.Result == null)
                {
                    // Per specification, If the property is single-valued and has the null value,
                    // the service responds with 204 No Content.
                    return(Request.CreateResponse(HttpStatusCode.NoContent));
                }

                return(response);
            }

            if (typeReference.IsCollection())
            {
                var elementType = typeReference.AsCollection().ElementType();
                if (elementType.IsPrimitive() || elementType.IsEnum())
                {
                    return(Request.CreateResponse(HttpStatusCode.OK, new NonResourceCollectionResult(query, typeReference)));
                }

                return(Request.CreateResponse(HttpStatusCode.OK, new ResourceSetResult(query, typeReference)));
            }

            var entityResult = query.SingleOrDefault();

            if (entityResult == null)
            {
                return(Request.CreateResponse(HttpStatusCode.NoContent));
            }

            // Check the ETag here
            if (etag != null)
            {
                // request with If-Match header, if match, then should return whole content
                // request with If-Match header, if not match, then should return 412
                // request with If-None-Match header, if match, then should return 304
                // request with If-None-Match header, if not match, then should return whole content
                etag.EntityType = query.ElementType;
                query           = etag.ApplyTo(query);
                entityResult    = query.SingleOrDefault();
                if (entityResult == null && !etag.IsIfNoneMatch)
                {
                    return(Request.CreateResponse(HttpStatusCode.PreconditionFailed));
                }
                else if (entityResult == null)
                {
                    return(Request.CreateResponse(HttpStatusCode.NotModified));
                }
            }

            // Using reflection to create response for single entity so passed in parameter is not object type,
            // but will be type of real entity type, then EtagMessageHandler can be used to set ETAG header
            // when response is single entity.
            // There are three HttpRequestMessageExtensions class defined in different assembles

            // Fix by @xuzhg in PR #609.
            var assembly      = System.Reflection.Assembly.GetAssembly(typeof(AcceptVerbsAttribute));
            var type          = assembly.GetType("System.Net.Http.HttpRequestMessageExtensions");
            var genericMethod = type.GetMethods()
                                .Where(m => m.Name == "CreateResponse" && m.GetParameters().Length == 3);
            var method = genericMethod.FirstOrDefault().MakeGenericMethod(query.ElementType);

            response = method.Invoke(null, new object[] { Request, HttpStatusCode.OK, entityResult }) as HttpResponseMessage;
            return(response);
        }
Exemplo n.º 9
0
        public void ApplyTo_NewQueryReturned_ForInteger(sbyte byteVal, short shortVal, bool ifMatch, IList <int> expect)
        {
            // Arrange
            var mycustomers = new List <MyETagOrder>
            {
                new MyETagOrder
                {
                    ID       = 1,
                    ByteVal  = 7,
                    ShortVal = 8
                },
                new MyETagOrder
                {
                    ID       = 2,
                    ByteVal  = SByte.MaxValue,
                    ShortVal = Int16.MaxValue
                },
                new MyETagOrder
                {
                    ID       = 3,
                    ByteVal  = SByte.MinValue,
                    ShortVal = Int16.MinValue
                },
            };
            IETagHandler handerl = new DefaultODataETagHandler();
            Dictionary <string, object> properties = new Dictionary <string, object>
            {
                { "ByteVal", byteVal },
                { "ShortVal", shortVal }
            };
            EntityTagHeaderValue etagHeaderValue = handerl.CreateETag(properties);

            var builder = ODataConventionModelBuilderFactory.Create();

            builder.EntitySet <MyETagOrder>("Orders");
            IEdmModel     model     = builder.GetEdmModel();
            IEdmEntitySet orders    = model.FindDeclaredEntitySet("Orders");
            ODataPath     odataPath = new ODataPath(new[] { new EntitySetSegment(orders) });
            var           request   = RequestFactory.CreateFromModel(model);

            request.ODataContext().Path = odataPath;

            ETag etagCustomer = request.GetETag(etagHeaderValue);

            etagCustomer.EntityType    = typeof(MyETagOrder);
            etagCustomer.IsIfNoneMatch = !ifMatch;

            // Act
            IQueryable queryable = etagCustomer.ApplyTo(mycustomers.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IEnumerable <MyETagOrder> actualOrders = Assert.IsAssignableFrom <IEnumerable <MyETagOrder> >(queryable);

            Assert.Equal(expect, actualOrders.Select(c => c.ID));
            MethodCallExpression methodCall = queryable.Expression as MethodCallExpression;

            Assert.NotNull(methodCall);
            Assert.Equal(2, methodCall.Arguments.Count);

            if (ifMatch)
            {
                Assert.Equal(
                    "Param_0 => ((Param_0.ByteVal == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.SByte]).TypedProperty) " +
                    "AndAlso (Param_0.ShortVal == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int16]).TypedProperty))",
                    methodCall.Arguments[1].ToString());
            }
            else
            {
                Assert.Equal(
                    "Param_0 => Not(((Param_0.ByteVal == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.SByte]).TypedProperty) " +
                    "AndAlso (Param_0.ShortVal == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int16]).TypedProperty)))",
                    methodCall.Arguments[1].ToString());
            }
        }
Exemplo n.º 10
0
        public void ApplyTo_NewQueryReturned_ForDouble(double value, bool ifMatch, IList <int> expect)
        {
            // Arrange
            var myCustomers = new List <MyETagCustomer>
            {
                new MyETagCustomer
                {
                    ID         = 1,
                    DoubleETag = 1.0,
                },
                new MyETagCustomer
                {
                    ID         = 2,
                    DoubleETag = 1.1,
                },
                new MyETagCustomer
                {
                    ID         = 3,
                    DoubleETag = 1.0,
                },
            };

            IETagHandler handerl = new DefaultODataETagHandler();
            Dictionary <string, object> properties = new Dictionary <string, object> {
                { "DoubleETag", value }
            };
            EntityTagHeaderValue etagHeaderValue = handerl.CreateETag(properties);

            var builder = ODataConventionModelBuilderFactory.Create();

            builder.EntitySet <MyETagCustomer>("Customers");
            IEdmModel      model     = builder.GetEdmModel();
            IEdmEntityType customer  = model.SchemaElements.OfType <IEdmEntityType>().FirstOrDefault(e => e.Name == "MyEtagCustomer");
            IEdmEntitySet  customers = model.FindDeclaredEntitySet("Customers");
            ODataPath      odataPath = new ODataPath(new[] { new EntitySetSegment(customers) });
            var            request   = RequestFactory.CreateFromModel(model);

            request.ODataContext().Path = odataPath;

            ETag etagCustomer = request.GetETag(etagHeaderValue);

            etagCustomer.EntityType    = typeof(MyETagCustomer);
            etagCustomer.IsIfNoneMatch = !ifMatch;

            // Act
            IQueryable queryable = etagCustomer.ApplyTo(myCustomers.AsQueryable());

            // Assert
            Assert.NotNull(queryable);
            IList <MyETagCustomer> actualCustomers = Assert.IsAssignableFrom <IEnumerable <MyETagCustomer> >(queryable).ToList();

            if (expect != null)
            {
                Assert.Equal(expect, actualCustomers.Select(c => c.ID));
            }

            MethodCallExpression methodCall = queryable.Expression as MethodCallExpression;

            Assert.NotNull(methodCall);
            Assert.Equal(2, methodCall.Arguments.Count);
            if (ifMatch)
            {
                Assert.Equal(
                    "Param_0 => (Param_0.DoubleETag == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Double]).TypedProperty)",
                    methodCall.Arguments[1].ToString());
            }
            else
            {
                Assert.Equal(
                    "Param_0 => Not((Param_0.DoubleETag == value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Double]).TypedProperty))",
                    methodCall.Arguments[1].ToString());
            }
        }
Exemplo n.º 11
0
        private IActionResult CreateQueryResponse(IQueryable query, IEdmType edmType, ETag etag)
        {
            var typeReference             = GetTypeReference(edmType);
            BaseSingleResult singleResult = null;
            IActionResult    response     = null;

            if (typeReference.IsPrimitive())
            {
                if (shouldReturnCount || shouldWriteRawValue)
                {
                    var rawResult = new RawResult(query, typeReference);
                    singleResult = rawResult;
                    response     = Ok(rawResult);
                }
                else
                {
                    var primitiveResult = new PrimitiveResult(query, typeReference);
                    singleResult = primitiveResult;
                    response     = Ok(primitiveResult);
                }
            }

            if (typeReference.IsComplex())
            {
                var complexResult = new ComplexResult(query, typeReference);
                singleResult = complexResult;
                response     = Ok(complexResult);
            }

            if (typeReference.IsEnum())
            {
                if (shouldWriteRawValue)
                {
                    var rawResult = new RawResult(query, typeReference);
                    singleResult = rawResult;
                    response     = Ok(rawResult);
                }
                else
                {
                    var enumResult = new EnumResult(query, typeReference);
                    singleResult = enumResult;
                    response     = Ok(enumResult);
                }
            }

            if (singleResult != null)
            {
                if (singleResult.Result == null)
                {
                    // Per specification, If the property is single-valued and has the null value,
                    // the service responds with 204 No Content.
                    return(NoContent());
                }

                return(response);
            }

            if (typeReference.IsCollection())
            {
                var elementType = typeReference.AsCollection().ElementType();
                if (elementType.IsPrimitive() || elementType.IsEnum())
                {
                    return(Ok(new NonResourceCollectionResult(query, typeReference)));
                }

                return(Ok(new ResourceSetResult(query, typeReference)));
            }

            var entityResult = query.SingleOrDefault();

            if (entityResult == null)
            {
                return(NoContent());
            }

            // Check the ETag here
            if (etag != null)
            {
                // request with If-Match header, if match, then should return whole content
                // request with If-Match header, if not match, then should return 412
                // request with If-None-Match header, if match, then should return 304
                // request with If-None-Match header, if not match, then should return whole content
                etag.EntityType = query.ElementType;
                query           = etag.ApplyTo(query);
                entityResult    = query.SingleOrDefault();
                if (entityResult == null && !etag.IsIfNoneMatch)
                {
                    return(StatusCode((int)HttpStatusCode.PreconditionFailed));
                }
                else if (entityResult == null)
                {
                    return(StatusCode((int)HttpStatusCode.NotModified));
                }
            }

            return(Ok(entityResult));
        }