diff --git a/src/Microsoft.AspNetCore.OData/Deltas/DeltaOfT.cs b/src/Microsoft.AspNetCore.OData/Deltas/DeltaOfT.cs index 6749a794c..4cfa6b89f 100644 --- a/src/Microsoft.AspNetCore.OData/Deltas/DeltaOfT.cs +++ b/src/Microsoft.AspNetCore.OData/Deltas/DeltaOfT.cs @@ -542,7 +542,7 @@ private void InitializeProperties(IEnumerable updatableProperties) } } - private bool IsIgnoredProperty(bool isTypeDataContract, PropertyInfo propertyInfo) + private static bool IsIgnoredProperty(bool isTypeDataContract, PropertyInfo propertyInfo) { //This is for Ignoring the property that matches below criteria //1. Its marked as NotMapped diff --git a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml index 47202d3a0..7c6895b51 100644 --- a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml +++ b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml @@ -1089,20 +1089,6 @@ The type to test. True if the type is a DateTime; false otherwise. - - - Determine if a type is a . - - The type to test. - True if the type is a DateOnly; false otherwise. - - - - Determine if a type is a . - - The type to test. - True if the type is a TimeOnly; false otherwise. - Determine if a type is a TimeSpan. @@ -6553,6 +6539,11 @@ Looks up a localized string similar to {0} does not support CreateODataValue.. + + + Looks up a localized string similar to Custom query option '{0}' that starts with '$' is not supported.. + + Looks up a localized string similar to The actual entity type '{0}' is not assignable to the expected type '{1}'.. @@ -14102,3 +14093,19 @@ +ummary> + The value segment. + + + + Gets the value segment. + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs b/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs index 860923b83..fee7dfc93 100644 --- a/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs +++ b/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs @@ -447,6 +447,15 @@ internal static string CreateODataValueNotSupported { } } + /// + /// Looks up a localized string similar to Custom query option '{0}' that starts with '$' is not supported.. + /// + internal static string CustomQueryOptionNotSupportedWithDollarSign { + get { + return ResourceManager.GetString("CustomQueryOptionNotSupportedWithDollarSign", resourceCulture); + } + } + /// /// Looks up a localized string similar to The actual entity type '{0}' is not assignable to the expected type '{1}'.. /// diff --git a/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx b/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx index 58ebedd25..90b303c9b 100644 --- a/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx +++ b/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx @@ -543,6 +543,9 @@ The requested resource is not a collection. Query options $filter, $orderby, $count, $skip, and $top can be applied only on collections. + + Custom query option '{0}' that starts with '$' is not supported. + The action '{0}' on controller '{1}' returned a {2} containing more than one element. {2} must have zero or one elements. diff --git a/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs b/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs index c8762a816..9a976865b 100644 --- a/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs +++ b/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs @@ -684,12 +684,12 @@ public virtual void ValidateQuery(HttpRequest request, ODataQueryOptions queryOp { if (request == null) { - throw Error.ArgumentNull("request"); + throw Error.ArgumentNull(nameof(request)); } if (queryOptions == null) { - throw Error.ArgumentNull("queryOptions"); + throw Error.ArgumentNull(nameof(queryOptions)); } IQueryCollection queryParameters = request.Query; @@ -700,7 +700,7 @@ public virtual void ValidateQuery(HttpRequest request, ODataQueryOptions queryOp { // we don't support any custom query options that start with $ // this should be caught be OnActionExecuted(). - throw new ArgumentOutOfRangeException(kvp.Key); + throw new ODataException(Error.Format(SRResources.CustomQueryOptionNotSupportedWithDollarSign, kvp.Key)); } } diff --git a/test/Microsoft.AspNetCore.OData.Tests/Query/EnableQueryAttributeTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Query/EnableQueryAttributeTests.cs index 51edc6b96..077f675a9 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/Query/EnableQueryAttributeTests.cs +++ b/test/Microsoft.AspNetCore.OData.Tests/Query/EnableQueryAttributeTests.cs @@ -6,23 +6,15 @@ //------------------------------------------------------------------------------ using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; using System.Linq; -using System.Net; -using System.Net.Http; using System.Reflection; -using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.OData.Extensions; using Microsoft.AspNetCore.OData.Query; -using Microsoft.AspNetCore.OData.TestCommon; using Microsoft.AspNetCore.OData.Tests.Commons; using Microsoft.AspNetCore.OData.Tests.Extensions; using Microsoft.AspNetCore.OData.Tests.Models; @@ -30,6 +22,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.OData; using Microsoft.OData.Edm; +using Microsoft.OData.ModelBuilder; using Microsoft.OData.UriParser; using Moq; using Xunit; @@ -38,6 +31,8 @@ namespace Microsoft.AspNetCore.OData.Tests.Query { public class EnableQueryAttributeTests { + private static IEdmModel _model = GetEdmModel(); + #if false public static List CustomerList = new List() { @@ -575,16 +570,15 @@ public void Primitives_Can_Be_Used_For_Top_And_Skip(string filter) Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(expectedResponse, response.Content); } +#endif [Fact] public void ValidateQuery_Throws_With_Null_Request() { // Arrange EnableQueryAttribute attribute = new EnableQueryAttribute(); - var request = RequestFactory.Create(); - request.EnableHttpDependencyInjectionSupport(); - var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Builder.TestModels.Customer)), request); + HttpRequest request = new DefaultHttpContext().Request; + var options = new ODataQueryOptions(new ODataQueryContext(EdmCoreModel.Instance, typeof(int)), request); // Act & Assert ExceptionAssert.ThrowsArgumentNull(() => attribute.ValidateQuery(null, options), "request"); @@ -595,9 +589,10 @@ public void ValidateQuery_Throws_WithNullQueryOptions() { // Arrange EnableQueryAttribute attribute = new EnableQueryAttribute(); + HttpRequest request = new DefaultHttpContext().Request; // Act & Assert - ExceptionAssert.ThrowsArgumentNull(() => attribute.ValidateQuery(new HttpRequestMessage(), null), "queryOptions"); + ExceptionAssert.ThrowsArgumentNull(() => attribute.ValidateQuery(request, null), "queryOptions"); } [Theory] @@ -609,15 +604,12 @@ public void ValidateQuery_Accepts_All_Supported_QueryNames(string query) { // Arrange EnableQueryAttribute attribute = new EnableQueryAttribute(); - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/?" + query); - request.EnableHttpDependencyInjectionSupport(); - DefaultQuerySettings defaultQuerySettings = request.GetConfiguration().GetDefaultQuerySettings(); - defaultQuerySettings.EnableFilter = true; - defaultQuerySettings.EnableOrderBy = true; - defaultQuerySettings.MaxTop = null; + HttpRequest request = RequestFactory.Create("Get", "http://localhost/?" + query); - var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); - var context = new ODataQueryContext(model, typeof(Builder.TestModels.Customer), null); + var context = new ODataQueryContext(_model, typeof(QCustomer)); + context.DefaultQuerySettings.EnableFilter = true; + context.DefaultQuerySettings.EnableOrderBy = true; + context.DefaultQuerySettings.MaxTop = null; var options = new ODataQueryOptions(context, request); // Act & Assert @@ -625,20 +617,18 @@ public void ValidateQuery_Accepts_All_Supported_QueryNames(string query) } [Fact] - public void ValidateQuery_Sends_BadRequest_For_Unrecognized_QueryNames() + public void ValidateQuery_ThrowsODataException_For_Unrecognized_QueryNames() { // Arrange EnableQueryAttribute attribute = new EnableQueryAttribute(); - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/?$xxx"); - request.EnableHttpDependencyInjectionSupport(); - var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Builder.TestModels.Customer)), request); + HttpRequest request = RequestFactory.Create("Get", "http://localhost/?$xxx"); + var options = new ODataQueryOptions(new ODataQueryContext(_model, typeof(QCustomer)), request); // Act & Assert - HttpResponseException responseException = ExceptionAssert.Throws( - () => attribute.ValidateQuery(request, options)); + ODataException ex = ExceptionAssert.Throws( + () => attribute.ValidateQuery(request, options)); - Assert.Equal(HttpStatusCode.BadRequest, responseException.Response.StatusCode); + Assert.Equal("Custom query option '$xxx' that starts with '$' is not supported.", ex.Message); } [Fact] @@ -646,13 +636,15 @@ public void ValidateQuery_Can_Override_Base() { // Arrange Mock mockAttribute = new Mock(); - mockAttribute.Setup(m => m.ValidateQuery(It.IsAny(), It.IsAny())).Callback(() => { }).Verifiable(); + mockAttribute.Setup( + m => m.ValidateQuery(It.IsAny(), It.IsAny())).Callback(() => { }).Verifiable(); // Act & Assert mockAttribute.Object.ValidateQuery(null, null); mockAttribute.Verify(); } +#if false [Fact] public void ApplyQuery_Throws_With_Null_Queryable() { @@ -1159,7 +1151,7 @@ public async Task OnActionExecuted_SingleResult_WithMoreThanASingleQueryResult_R "returned a SingleResult containing more than one element. SingleResult must have zero or one elements.", responseString); } - +#endif [Theory] [InlineData("$filter=ID eq 1")] [InlineData("$orderby=ID")] @@ -1168,18 +1160,18 @@ public async Task OnActionExecuted_SingleResult_WithMoreThanASingleQueryResult_R [InlineData("$top=0")] 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); - request.EnableHttpDependencyInjectionSupport(); - ODataQueryContext context = new ODataQueryContext(model.Model, typeof(Customer)); + // Arrange + HttpRequest request = RequestFactory.Create("Get", "http://localhost?" + parameter); + ODataQueryContext context = new ODataQueryContext(_model, typeof(QCustomer)); ODataQueryOptions queryOptions = new ODataQueryOptions(context, request); + // Act & Assert ExceptionAssert.Throws( () => EnableQueryAttribute.ValidateSelectExpandOnly(queryOptions), "The requested resource is not a collection. Query options $filter, $orderby, $count, $skip, and $top can be applied only on collections."); } +#if false [Fact] public void OnActionExecuted_Works_WithPath() { @@ -1249,5 +1241,17 @@ private static HttpActionExecutedContext GetActionExecutedContext(str return actionExecutedContext; } #endif + private static IEdmModel GetEdmModel() + { + var builder = new ODataConventionModelBuilder(); + builder.EntitySet("Customers"); + return builder.GetEdmModel(); + } + + private class QCustomer + { + public int Id { get; set; } + public string Name { get; set; } + } } }