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()); }
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()); }
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()); }
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 }
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); }
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); }
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); }
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); }
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()); } }
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()); } }
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)); }