diff --git a/src/Microsoft.AspNet.OData.Shared/Common/SRResources.Designer.cs b/src/Microsoft.AspNet.OData.Shared/Common/SRResources.Designer.cs index e94f1e7886..efaa79fe53 100644 --- a/src/Microsoft.AspNet.OData.Shared/Common/SRResources.Designer.cs +++ b/src/Microsoft.AspNet.OData.Shared/Common/SRResources.Designer.cs @@ -465,6 +465,17 @@ internal static string CantFindEdmType } } + /// + /// Looks up a localized string similar to Cannot find ClrType corresponding to EdmType {0}. + /// + internal static string CannotFindClrType + { + get + { + return ResourceManager.GetString("CannotFindClrType", resourceCulture); + } + } + /// /// Looks up a localized string similar to The given model does not contain the type '{0}'.. /// diff --git a/src/Microsoft.AspNet.OData.Shared/EnableQueryAttribute.cs b/src/Microsoft.AspNet.OData.Shared/EnableQueryAttribute.cs index c2cc1b0e04..da0fd4be23 100644 --- a/src/Microsoft.AspNet.OData.Shared/EnableQueryAttribute.cs +++ b/src/Microsoft.AspNet.OData.Shared/EnableQueryAttribute.cs @@ -387,7 +387,7 @@ private object OnActionExecuted( IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func modelFunction, - Func createQueryOptionFunction, + Func createQueryOptionFunction, Action createResponseAction, Action createErrorAction) { @@ -466,9 +466,9 @@ private object OnActionExecuted( /// /// The original queryable instance from the response message. /// - /// The instance constructed based on the incoming request. + /// The instance constructed based on the incoming request. /// - public virtual IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions) + public virtual IQueryable ApplyQuery(IQueryable queryable, IODataQueryOptions queryOptions) { if (queryable == null) { @@ -487,10 +487,10 @@ public virtual IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions que /// /// The original entity from the response message. /// - /// The instance constructed based on the incoming request. + /// The instance constructed based on the incoming request. /// /// The new entity after the $select and $expand query has been applied to. - public virtual object ApplyQuery(object entity, ODataQueryOptions queryOptions) + public virtual object ApplyQuery(object entity, IODataQueryOptions queryOptions) { if (entity == null) { @@ -588,12 +588,12 @@ private object ExecuteQuery( IWebApiActionDescriptor actionDescriptor, Func modelFunction, IWebApiRequestMessage request, - Func createQueryOptionFunction) + Func createQueryOptionFunction) { ODataQueryContext queryContext = GetODataQueryContext(responseValue, singleResultCollection, actionDescriptor, modelFunction, request.Context.Path); // Create and validate the query options. - ODataQueryOptions queryOptions = createQueryOptionFunction(queryContext); + IODataQueryOptions queryOptions = createQueryOptionFunction(queryContext); // apply the query IEnumerable enumerable = responseValue as IEnumerable; @@ -718,7 +718,7 @@ internal static object SingleOrDefault( /// Validate the select and expand options. /// /// The query options. - internal static void ValidateSelectExpandOnly(ODataQueryOptions queryOptions) + internal static void ValidateSelectExpandOnly(IODataQueryOptions queryOptions) { if (queryOptions.Filter != null || queryOptions.Count != null || queryOptions.OrderBy != null || queryOptions.Skip != null || queryOptions.Top != null) diff --git a/src/Microsoft.AspNet.OData.Shared/Formatter/Serialization/ODataSerializerContext.cs b/src/Microsoft.AspNet.OData.Shared/Formatter/Serialization/ODataSerializerContext.cs index f98cfce09c..a5882b85b6 100644 --- a/src/Microsoft.AspNet.OData.Shared/Formatter/Serialization/ODataSerializerContext.cs +++ b/src/Microsoft.AspNet.OData.Shared/Formatter/Serialization/ODataSerializerContext.cs @@ -229,9 +229,9 @@ internal ExpandedReferenceSelectItem CurrentExpandedSelectItem internal SelectItem CurrentSelectItem { get; set; } /// - /// Gets or sets the . + /// Gets or sets the . /// - public ODataQueryOptions QueryOptions { get; internal set; } + public IODataQueryOptions QueryOptions { get; internal set; } /// /// Gets or sets the relative path to the resouce being serialized diff --git a/src/Microsoft.AspNet.OData.Shared/Interfaces/IWebApiContext.cs b/src/Microsoft.AspNet.OData.Shared/Interfaces/IWebApiContext.cs index 0406ca70e6..90949dc0ec 100644 --- a/src/Microsoft.AspNet.OData.Shared/Interfaces/IWebApiContext.cs +++ b/src/Microsoft.AspNet.OData.Shared/Interfaces/IWebApiContext.cs @@ -63,9 +63,9 @@ internal interface IWebApiContext SelectExpandClause ProcessedSelectExpandClause { get; set; } /// - /// Gets or sets the of the request. + /// Gets or sets the of the request. /// - ODataQueryOptions QueryOptions { get; set; } + IODataQueryOptions QueryOptions { get; set; } /// /// Gets or sets the total count for the OData response. diff --git a/src/Microsoft.AspNet.OData.Shared/ODataQueryParameterBindingAttribute.cs b/src/Microsoft.AspNet.OData.Shared/ODataQueryParameterBindingAttribute.cs index 3aa5cfd598..fb28613161 100644 --- a/src/Microsoft.AspNet.OData.Shared/ODataQueryParameterBindingAttribute.cs +++ b/src/Microsoft.AspNet.OData.Shared/ODataQueryParameterBindingAttribute.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics.Contracts; using System.Linq; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; namespace Microsoft.AspNet.OData @@ -18,7 +19,8 @@ internal static Type GetEntityClrTypeFromParameterType(Type parameterType) Contract.Assert(parameterType != null); if (parameterType.IsGenericType && - parameterType.GetGenericTypeDefinition() == typeof(ODataQueryOptions<>)) + (parameterType.GetGenericTypeDefinition() == typeof(ODataQueryOptions<>) || + parameterType.GetGenericTypeDefinition() == typeof(IODataQueryOptions<>))) { return parameterType.GetGenericArguments().Single(); } diff --git a/src/Microsoft.AspNet.OData.Shared/Query/DefaultSkipTokenHandler.cs b/src/Microsoft.AspNet.OData.Shared/Query/DefaultSkipTokenHandler.cs index bccaaf3b62..d1c832bee2 100644 --- a/src/Microsoft.AspNet.OData.Shared/Query/DefaultSkipTokenHandler.cs +++ b/src/Microsoft.AspNet.OData.Shared/Query/DefaultSkipTokenHandler.cs @@ -10,6 +10,7 @@ using Microsoft.AspNet.OData.Common; using Microsoft.AspNet.OData.Formatter; using Microsoft.AspNet.OData.Formatter.Serialization; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query.Expressions; using Microsoft.OData; using Microsoft.OData.Edm; @@ -181,7 +182,7 @@ public override IQueryable ApplyTo(IQueryable query, SkipTokenQueryOption skipTo } ODataQuerySettings querySettings = skipTokenQueryOption.QuerySettings; - ODataQueryOptions queryOptions = skipTokenQueryOption.QueryOptions; + IODataQueryOptions queryOptions = skipTokenQueryOption.QueryOptions; IList orderByNodes = null; if (queryOptions != null) diff --git a/src/Microsoft.AspNet.OData.Shared/Query/ODataQueryOptions.cs b/src/Microsoft.AspNet.OData.Shared/Query/ODataQueryOptions.cs index b9b5545168..683c3d549c 100644 --- a/src/Microsoft.AspNet.OData.Shared/Query/ODataQueryOptions.cs +++ b/src/Microsoft.AspNet.OData.Shared/Query/ODataQueryOptions.cs @@ -52,7 +52,7 @@ public partial class ODataQueryOptions private OrderByQueryOption _stableOrderBy; /// - /// Initializes a new instance of the class based on the incoming request and some metadata information from + /// Initializes a new instance of the class based on the incoming request and some metadata information from /// the . /// /// The which contains the and some type information. diff --git a/src/Microsoft.AspNet.OData.Shared/Query/SkipTokenQueryOption.cs b/src/Microsoft.AspNet.OData.Shared/Query/SkipTokenQueryOption.cs index cd08e2c96c..654b4a7772 100644 --- a/src/Microsoft.AspNet.OData.Shared/Query/SkipTokenQueryOption.cs +++ b/src/Microsoft.AspNet.OData.Shared/Query/SkipTokenQueryOption.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNet.OData.Common; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query.Validators; using Microsoft.OData.Edm; using Microsoft.OData.UriParser; @@ -74,7 +75,7 @@ public SkipTokenQueryOption(string rawValue, ODataQueryContext context, ODataQue /// /// Gets or sets the QueryOptions /// - public ODataQueryOptions QueryOptions { get; private set; } + public IODataQueryOptions QueryOptions { get; private set; } /// /// Apply the $skiptoken query to the given IQueryable. @@ -83,7 +84,7 @@ public SkipTokenQueryOption(string rawValue, ODataQueryContext context, ODataQue /// The query settings to use while applying this query option. /// Information about the other query options. /// The new after the skiptoken query has been applied to. - public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, ODataQueryOptions queryOptions) + public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, IODataQueryOptions queryOptions) { QuerySettings = querySettings; QueryOptions = queryOptions; @@ -97,7 +98,7 @@ public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings /// The query settings to use while applying this query option. /// Information about the other query options. /// The new after the skiptoken query has been applied to. - public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, ODataQueryOptions queryOptions) + public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, IODataQueryOptions queryOptions) { QuerySettings = querySettings; QueryOptions = queryOptions; diff --git a/src/Microsoft.AspNet.OData.Shared/Query/Validators/ODataQueryValidator.cs b/src/Microsoft.AspNet.OData.Shared/Query/Validators/ODataQueryValidator.cs index ce907a7388..6a6207b3a7 100644 --- a/src/Microsoft.AspNet.OData.Shared/Query/Validators/ODataQueryValidator.cs +++ b/src/Microsoft.AspNet.OData.Shared/Query/Validators/ODataQueryValidator.cs @@ -2,8 +2,10 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using Microsoft.AspNet.OData.Common; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.Extensions.DependencyInjection; using Microsoft.OData; +using System; namespace Microsoft.AspNet.OData.Query.Validators { @@ -17,7 +19,7 @@ public class ODataQueryValidator /// /// The OData query to validate. /// The validation settings. - public virtual void Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) + public virtual void Validate(IODataQueryOptions options, ODataValidationSettings validationSettings) { if (options == null) { @@ -62,15 +64,22 @@ public virtual void Validate(ODataQueryOptions options, ODataValidationSettings options.Filter.Validate(validationSettings); } - if (options.Count != null || options.InternalRequest.IsCountRequest()) + if (options is ODataQueryOptions _options) { - ValidateQueryOptionAllowed(AllowedQueryOptions.Count, validationSettings.AllowedQueryOptions); - - if (options.Count != null) + if (_options.Count != null || _options.InternalRequest.IsCountRequest()) { - options.Count.Validate(validationSettings); + ValidateQueryOptionAllowed(AllowedQueryOptions.Count, validationSettings.AllowedQueryOptions); + + if (_options.Count != null) + { + _options.Count.Validate(validationSettings); + } } } + else + { + throw new NotSupportedException(); + } if (options.SkipToken != null) { diff --git a/src/Microsoft.AspNetCore.OData/Adapters/WebApiContext.cs b/src/Microsoft.AspNetCore.OData/Adapters/WebApiContext.cs index 7b013021ec..31d289b9d1 100644 --- a/src/Microsoft.AspNetCore.OData/Adapters/WebApiContext.cs +++ b/src/Microsoft.AspNetCore.OData/Adapters/WebApiContext.cs @@ -93,15 +93,14 @@ public SelectExpandClause ProcessedSelectExpandClause } /// - /// Gets or sets the parsed of the request. + /// Gets or sets the parsed of the request. /// - public ODataQueryOptions QueryOptions + public IODataQueryOptions QueryOptions { get { // since we wanted to avoid a breaking change by modifying the interface, we cast to check if it is our ODataFeature class before we access the internal property. To be cleaned up with 8.x. - ODataFeature feature = this.innerFeature as ODataFeature; - if (feature != null) + if (this.innerFeature is ODataFeature feature) { return feature.QueryOptions; } @@ -110,8 +109,7 @@ public ODataQueryOptions QueryOptions } set { - ODataFeature feature = this.innerFeature as ODataFeature; - if (feature != null) + if (this.innerFeature is ODataFeature feature) { feature.QueryOptions = value; } @@ -135,8 +133,7 @@ public int PageSize get { // since we wanted to avoid a breaking change by modifying the interface, we cast to check if it is our ODataFeature class before we access the internal property. - ODataFeature feature = this.innerFeature as ODataFeature; - if (feature != null) + if (this.innerFeature is ODataFeature feature) { return feature.PageSize; } @@ -145,8 +142,7 @@ public int PageSize } set { - ODataFeature feature = this.innerFeature as ODataFeature; - if (feature != null) + if (this.innerFeature is ODataFeature feature) { feature.PageSize = value; } diff --git a/src/Microsoft.AspNetCore.OData/EnableQueryAttribute.cs b/src/Microsoft.AspNetCore.OData/EnableQueryAttribute.cs index ff5cb93741..b67f192da9 100644 --- a/src/Microsoft.AspNetCore.OData/EnableQueryAttribute.cs +++ b/src/Microsoft.AspNetCore.OData/EnableQueryAttribute.cs @@ -11,6 +11,7 @@ using Microsoft.AspNet.OData.Common; using Microsoft.AspNet.OData.Extensions; using Microsoft.AspNet.OData.Formatter; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -118,14 +119,14 @@ public override void OnActionExecuted(ActionExecutedContext actionExecutedContex } /// - /// Create and validate a new instance of from a query and context. + /// Create and validate a new instance of from a query and context. /// /// The incoming request. /// The query context. /// - private ODataQueryOptions CreateAndValidateQueryOptions(HttpRequest request, ODataQueryContext queryContext) + private IODataQueryOptions CreateAndValidateQueryOptions(HttpRequest request, ODataQueryContext queryContext) { - ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, request); + IODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, request); ValidateQuery(request, queryOptions); return queryOptions; @@ -191,11 +192,11 @@ private static BadRequestObjectResult CreateBadRequestResult(string message, Exc /// /// The incoming request. /// - /// The instance constructed based on the incoming request. + /// The instance constructed based on the incoming request. /// [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Response disposed after being sent.")] - public virtual void ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions) + public virtual void ValidateQuery(HttpRequest request, IODataQueryOptions queryOptions) { if (request == null) { diff --git a/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptions.cs b/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptions.cs index ffbdd4cc75..71e1150b78 100644 --- a/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptions.cs +++ b/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptions.cs @@ -10,6 +10,8 @@ namespace Microsoft.AspNet.OData.Interfaces /// This defines a composite OData query options that can be used to perform query composition. /// Currently this only supports $filter, $orderby, $top, $skip, and $count. /// + [ODataQueryParameterBinding] + [NonValidatingParameterBinding] public interface IODataQueryOptions { /// diff --git a/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptionsOfTEntity.cs b/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptionsOfTEntity.cs index 552fbe7ab9..765f6fbfd2 100644 --- a/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptionsOfTEntity.cs +++ b/src/Microsoft.AspNetCore.OData/Interfaces/IODataQueryOptionsOfTEntity.cs @@ -9,6 +9,7 @@ namespace Microsoft.AspNet.OData.Interfaces /// This defines a composite OData query options that can be used to perform query composition. /// Currently this only supports $filter, $orderby, $top, $skip. /// + [ODataQueryParameterBinding] public interface IODataQueryOptions : IODataQueryOptions { diff --git a/src/Microsoft.AspNetCore.OData/NonValidatingParameterBindingAttribute.cs b/src/Microsoft.AspNetCore.OData/NonValidatingParameterBindingAttribute.cs index a72736d1fb..989e67fc13 100644 --- a/src/Microsoft.AspNetCore.OData/NonValidatingParameterBindingAttribute.cs +++ b/src/Microsoft.AspNetCore.OData/NonValidatingParameterBindingAttribute.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNet.OData /// /// This is essentially a . /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] internal sealed partial class NonValidatingParameterBindingAttribute : ModelBinderAttribute, IPropertyValidationFilter { /// diff --git a/src/Microsoft.AspNetCore.OData/ODataFeature.cs b/src/Microsoft.AspNetCore.OData/ODataFeature.cs index 225389920b..c5f74e62f1 100644 --- a/src/Microsoft.AspNetCore.OData/ODataFeature.cs +++ b/src/Microsoft.AspNetCore.OData/ODataFeature.cs @@ -145,9 +145,9 @@ public long? TotalCount public IDictionary RoutingConventionsStore { get; set; } = new Dictionary(); /// - /// Gets or sets the parsed of the request. + /// Gets or sets the parsed of the request. /// - internal ODataQueryOptions QueryOptions { get; set; } + internal IODataQueryOptions QueryOptions { get; set; } /// /// Page size to be used by skiptoken implementation for the top-level resource for the request. diff --git a/src/Microsoft.AspNetCore.OData/ODataQueryParameterBindingAttribute.cs b/src/Microsoft.AspNetCore.OData/ODataQueryParameterBindingAttribute.cs index 7654037921..29a4448ba2 100644 --- a/src/Microsoft.AspNetCore.OData/ODataQueryParameterBindingAttribute.cs +++ b/src/Microsoft.AspNetCore.OData/ODataQueryParameterBindingAttribute.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.OData.Common; using Microsoft.AspNet.OData.Extensions; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -19,9 +20,9 @@ namespace Microsoft.AspNet.OData { /// - /// A to bind parameters of type to the OData query from the incoming request. + /// A to bind parameters of type to the OData query from the incoming request. /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] public sealed partial class ODataQueryParameterBindingAttribute : ModelBinderAttribute { /// @@ -88,20 +89,20 @@ public Task BindModelAsync(ModelBindingContext bindingContext) IEdmModel model = userModel != EdmCoreModel.Instance ? userModel : actionDescriptor.GetEdmModel(request, entityClrType); ODataQueryContext entitySetContext = new ODataQueryContext(model, entityClrType, request.ODataFeature().Path); - Func createODataQueryOptions; + Func createODataQueryOptions; object constructorAsObject = null; if (actionDescriptor.Properties.TryGetValue(CreateODataQueryOptionsCtorKey, out constructorAsObject)) { - createODataQueryOptions = (Func)constructorAsObject; + createODataQueryOptions = (Func)constructorAsObject; } else { - createODataQueryOptions = (Func) - Delegate.CreateDelegate(typeof(Func), + createODataQueryOptions = (Func) + Delegate.CreateDelegate(typeof(Func), _createODataQueryOptions.MakeGenericMethod(entityClrType)); }; - ODataQueryOptions parameterValue = createODataQueryOptions(entitySetContext, request); + IODataQueryOptions parameterValue = createODataQueryOptions(entitySetContext, request); bindingContext.Result = ModelBindingResult.Success(parameterValue); } @@ -114,12 +115,17 @@ public static bool IsODataQueryOptions(Type parameterType) { return false; } - return ((parameterType == typeof(ODataQueryOptions)) || + + bool isODataParameter = ((parameterType == typeof(ODataQueryOptions) || + parameterType == typeof(IODataQueryOptions)) || (parameterType.IsGenericType && - parameterType.GetGenericTypeDefinition() == typeof(ODataQueryOptions<>))); + (parameterType.GetGenericTypeDefinition() == typeof(ODataQueryOptions<>) || + parameterType.GetGenericTypeDefinition() == typeof(IODataQueryOptions<>)))); + + return isODataParameter; } - public static ODataQueryOptions CreateODataQueryOptions(ODataQueryContext context, HttpRequest request) + public static IODataQueryOptions CreateODataQueryOptions(ODataQueryContext context, HttpRequest request) { return new ODataQueryOptions(context, request); } diff --git a/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptions.cs b/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptions.cs index bb23365a9a..c637a8a1eb 100644 --- a/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptions.cs +++ b/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptions.cs @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using System.Diagnostics.Contracts; using Microsoft.AspNet.OData.Adapters; using Microsoft.AspNet.OData.Common; using Microsoft.AspNet.OData.Extensions; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNetCore.Http; using Microsoft.OData.Edm; diff --git a/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptionsOfTEntity.cs b/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptionsOfTEntity.cs index b08648058a..3c0aebd999 100644 --- a/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptionsOfTEntity.cs +++ b/src/Microsoft.AspNetCore.OData/Query/ODataQueryOptionsOfTEntity.cs @@ -2,8 +2,11 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using Microsoft.AspNet.OData.Common; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Edm; +using System; namespace Microsoft.AspNet.OData.Query { @@ -11,7 +14,8 @@ namespace Microsoft.AspNet.OData.Query /// This defines a composite OData query options that can be used to perform query composition. /// Currently this only supports $filter, $orderby, $top, $skip. /// - public partial class ODataQueryOptions : ODataQueryOptions + public partial class ODataQueryOptions + : ODataQueryOptions { /// /// Initializes a new instance of the class based on the incoming request and some metadata information from diff --git a/src/Microsoft.AspNetCore.OData/Query/QueryFilterProvider.cs b/src/Microsoft.AspNetCore.OData/Query/QueryFilterProvider.cs index 0d48649c55..d2e8e7c935 100644 --- a/src/Microsoft.AspNetCore.OData/Query/QueryFilterProvider.cs +++ b/src/Microsoft.AspNetCore.OData/Query/QueryFilterProvider.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNet.OData.Common; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; @@ -13,7 +14,7 @@ namespace Microsoft.AspNet.OData.Query /// /// An implementation of that applies an action filter to /// any action with an or return type - /// that doesn't bind a parameter of type . + /// that doesn't bind a parameter of type . /// public class QueryFilterProvider : IFilterProvider { diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/ODataFormatterTests.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/ODataFormatterTests.cs index 895d3b184f..4ce554d592 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/ODataFormatterTests.cs +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/ODataFormatterTests.cs @@ -12,9 +12,11 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNet.OData.Builder; +using Microsoft.AspNet.OData.Common; using Microsoft.AspNet.OData.Extensions; using Microsoft.AspNet.OData.Formatter; using Microsoft.AspNet.OData.Formatter.Serialization; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNet.OData.Routing; using Microsoft.AspNet.OData.Routing.Conventions; @@ -627,14 +629,17 @@ public async Task RequestProperty_HasCorrectContextUrl() } } - [Fact] - public async Task ODataCollectionSerializer_SerializeIQueryableOfIEdmEntityObject() + + [Theory] + [InlineData(typeof(Class.CollectionSerializerCustomersController))] + [InlineData(typeof(Interface.CollectionSerializerCustomersController))] + public async Task ODataCollectionSerializer_SerializeIQueryableOfIEdmEntityObject(Type controller) { // Arrange ODataConventionModelBuilder builder = ODataConventionModelBuilderFactory.Create(); builder.EntitySet("CollectionSerializerCustomers"); IEdmModel model = builder.GetEdmModel(); - var controllers = new[] { typeof(CollectionSerializerCustomersController) }; + var controllers = new[] { controller }; var server = TestServerFactory.Create(controllers, (config) => { config.MapODataServiceRoute("odata", null, model); @@ -983,29 +988,6 @@ private static void AssertMultipleKey(string key1, Date key2, Guid key3) Assert.Equal(new Guid("46538EC2-E497-4DFE-A039-1C22F0999D6C"), key3); } - public class CollectionSerializerCustomer - { - public int ID { get; set; } - public string Name { get; set; } - } - - public class CollectionSerializerCustomersController : TestODataController - { - public ITestActionResult Get(ODataQueryOptions options) - { - IQueryable customers = new[] - { - new CollectionSerializerCustomer{ID = 1, Name = "Name 1"}, - new CollectionSerializerCustomer{ID = 2, Name = "Name 2"}, - new CollectionSerializerCustomer{ID = 3, Name = "Name 3"}, - }.AsQueryable(); - - IQueryable appliedCustomers = options.ApplyTo(customers) as IQueryable; - - return Ok(appliedCustomers); - } - } - private static void AddDataServiceVersionHeaders(HttpRequestMessage request) { request.Headers.Add("OData-Version", "4.0"); @@ -1038,7 +1020,7 @@ private static HttpClient CreateClient(IEdmModel model = null, var controllers = new[] { typeof(MainEntityController), typeof(PeopleController), typeof(EnumCustomersController), - typeof(CollectionSerializerCustomersController), typeof(PresidentController) + typeof(Class.CollectionSerializerCustomersController), typeof(PresidentController) }; var server = TestServerFactory.CreateWithFormatters(controllers, null, (config) => diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/SUT/CollectionSerializerCustomer.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/SUT/CollectionSerializerCustomer.cs new file mode 100644 index 0000000000..38d03edab2 --- /dev/null +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/SUT/CollectionSerializerCustomer.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.AspNet.OData.Test.Formatter +{ + public class CollectionSerializerCustomer + { + public int ID { get; set; } + public string Name { get; set; } + } +} diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/SUT/CollectionSerializerCustomersController.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/SUT/CollectionSerializerCustomersController.cs new file mode 100644 index 0000000000..6c9e067080 --- /dev/null +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Formatter/SUT/CollectionSerializerCustomersController.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNet.OData.Interfaces; +using Microsoft.AspNet.OData.Query; +using Microsoft.AspNet.OData.Test.Abstraction; +using System.Linq; + +namespace Microsoft.AspNet.OData.Test.Formatter.Class +{ + public class CollectionSerializerCustomersController : TestODataController + { + public ITestActionResult Get(ODataQueryOptions options) + { + IQueryable customers = new[] + { + new CollectionSerializerCustomer{ID = 1, Name = "Name 1"}, + new CollectionSerializerCustomer{ID = 2, Name = "Name 2"}, + new CollectionSerializerCustomer{ID = 3, Name = "Name 3"}, + }.AsQueryable(); + + IQueryable appliedCustomers = options.ApplyTo(customers) as IQueryable; + + return Ok(appliedCustomers); + } + } +} + +namespace Microsoft.AspNet.OData.Test.Formatter.Interface +{ + public class CollectionSerializerCustomersController : TestODataController + { + public ITestActionResult Get(IODataQueryOptions options) + { + IQueryable customers = new[] + { + new CollectionSerializerCustomer{ID = 1, Name = "Name 1"}, + new CollectionSerializerCustomer{ID = 2, Name = "Name 2"}, + new CollectionSerializerCustomer{ID = 3, Name = "Name 3"}, + }.AsQueryable(); + + IQueryable appliedCustomers = options.ApplyTo(customers) as IQueryable; + + return Ok(appliedCustomers); + } + } +} diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Microsoft.AspNet.OData.Test.Shared.projitems b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Microsoft.AspNet.OData.Test.Shared.projitems index e845a35797..7f6cfb3532 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Microsoft.AspNet.OData.Test.Shared.projitems +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Microsoft.AspNet.OData.Test.Shared.projitems @@ -222,6 +222,8 @@ + + diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ApplyQueryOptionTest.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ApplyQueryOptionTest.cs index 78f8e560af..a83adda3b4 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ApplyQueryOptionTest.cs +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ApplyQueryOptionTest.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.OData.Builder; using Microsoft.AspNet.OData.Extensions; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNet.OData.Query.Expressions; using Microsoft.AspNet.OData.Test.Abstraction; @@ -1268,7 +1269,7 @@ public void ClausesAfterApplyTo_Returns_Correct_Queryable(string filter, List customers = CustomerApplyTestData; // Act @@ -1312,7 +1313,7 @@ public void ClausesWithGroupedOutReferences_Throw_ODataException(string clause) var configuration = RoutingConfigurationFactory.CreateWithRootContainer("OData"); var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + clause, configuration, "OData"); - var options = new ODataQueryOptions(context, request); + IODataQueryOptions options = new ODataQueryOptions(context, request); IEnumerable customers = CustomerApplyTestData; @@ -1344,7 +1345,7 @@ public void StableSortingAndPagingApplyTo_Returns_Correct_Queryable(string filte var configuration = RoutingConfigurationFactory.CreateWithRootContainer("OData"); var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + filter, configuration, "OData"); - var options = new ODataQueryOptions(context, request); + IODataQueryOptions options = new ODataQueryOptions(context, request); IEnumerable customers = CustomerApplyTestData; // Act diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionParserExtensionTest.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionParserExtensionTest.cs index ef5cb8de39..13f4925a12 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionParserExtensionTest.cs +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionParserExtensionTest.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net.Http; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNet.OData.Test.Abstraction; using Microsoft.AspNet.OData.Test.Routing; @@ -23,7 +24,7 @@ public void Filter_Works_QueryOptionCaseInsensitive() const string filter = "$FiLtEr=name eQ 'nba'"; // Act - ODataQueryOptions queryOptions = GetQueryOptions(filter); + IODataQueryOptions queryOptions = GetQueryOptions(filter); // Assert Assert.NotNull(queryOptions.Filter); @@ -39,7 +40,7 @@ public void OrderBy_Works_QueryOptionCaseInsensitive() const string orderBy = "$oRdeRby=naMe"; // Act - ODataQueryOptions queryOptions = GetQueryOptions(orderBy); + IODataQueryOptions queryOptions = GetQueryOptions(orderBy); // Assert Assert.NotNull(queryOptions.OrderBy); @@ -55,7 +56,7 @@ public void Select_Works_QueryOptionCaseInsensitive() const string select = "$SeLecT=naMe"; // Act - ODataQueryOptions queryOptions = GetQueryOptions(select); + IODataQueryOptions queryOptions = GetQueryOptions(select); // Assert Assert.NotNull(queryOptions.SelectExpand); @@ -74,7 +75,7 @@ public void Expand_Works_QueryOptionCaseInsensitive() const string expand = "$ExPAnd=ProdUCts"; // Act - ODataQueryOptions queryOptions = GetQueryOptions(expand); + IODataQueryOptions queryOptions = GetQueryOptions(expand); // Assert Assert.NotNull(queryOptions.SelectExpand); @@ -86,7 +87,7 @@ public void Expand_Works_QueryOptionCaseInsensitive() Assert.Equal("Products", segment.NavigationProperty.Name); } - private static ODataQueryOptions GetQueryOptions(string queryOption) + private static IODataQueryOptions GetQueryOptions(string queryOption) { string uri = "Http://localhost/RoutingCustomers?" + queryOption; diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionTest.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionTest.cs index 554e3e5bc9..b60899a2f6 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionTest.cs +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/ODataQueryOptionTest.cs @@ -557,7 +557,7 @@ public void OrderbyWithUnknownPropertyThrows() "http://server/service/Customers?$orderby=UnknownProperty" ); - var option = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions option = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); ExceptionAssert.Throws(() => { option.ApplyTo(new List().AsQueryable()); @@ -574,7 +574,7 @@ public void CannotConvertBadTopQueryThrows() "http://server/service/Customers?$top=NotANumber" ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); ExceptionAssert.Throws(() => options.ApplyTo(Customers), "Invalid value 'NotANumber' for $top query option found. " + @@ -602,7 +602,7 @@ public void CannotConvertBadSkipQueryThrows() "http://server/service/Customers?$skip=NotANumber" ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); ExceptionAssert.Throws(() => options.ApplyTo(Customers), "Invalid value 'NotANumber' for $skip query option found. " + @@ -642,7 +642,7 @@ public void ApplyTo_Picks_DefaultOrder(string oDataQuery, Type elementType, stri "http://server/service/entityset?" + oDataQuery ); - var options = new ODataQueryOptions(new ODataQueryContext(model, elementType), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, elementType), message); IQueryable finalQuery = options.ApplyTo(query); string queryExpression = ExpressionStringBuilder.ToString(finalQuery.Expression); @@ -663,7 +663,7 @@ public void ApplyTo_DoesnotPickDefaultOrder_IfSkipAndTopAreNotPresent(string oDa "http://server/service/Customers?" + oDataQuery ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); IQueryable finalQuery = options.ApplyTo(Customers); string queryExpression = finalQuery.Expression.ToString(); @@ -684,7 +684,7 @@ public void ApplyTo_DoesnotPickDefaultOrder_IfOrderByIsPresent(string oDataQuery "http://server/service/Customers?" + oDataQuery ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); IQueryable finalQuery = options.ApplyTo(Customers); string queryExpression = ExpressionStringBuilder.ToString(finalQuery.Expression); @@ -707,7 +707,7 @@ public void ApplyTo_Builds_Default_OrderBy_With_Keys(string oDataQuery, bool ens "http://server/service/Customers?" + oDataQuery ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); ODataQuerySettings querySettings = new ODataQuerySettings { EnsureStableOrdering = ensureStableOrdering @@ -735,7 +735,7 @@ public void ApplyTo_Builds_Default_OrderBy_No_Keys(string oDataQuery, bool ensur "http://server/service/Customers?" + oDataQuery ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); ODataQuerySettings querySettings = new ODataQuerySettings { EnsureStableOrdering = ensureStableOrdering @@ -759,7 +759,7 @@ public void Validate_ThrowsValidationErrors_ForOrderBy() "http://server/service/Customers?$orderby=CustomerId,Name" ); - var options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); + IODataQueryOptions options = new ODataQueryOptions(new ODataQueryContext(model, typeof(Customer)), message); ODataValidationSettings validationSettings = new ODataValidationSettings { MaxOrderByNodeCount = 1 }; // Act & Assert @@ -815,7 +815,7 @@ public void CanTurnOffAllValidation() ); ODataQueryContext context = ValidationTestHelper.CreateCustomerContext(false); - ODataQueryOptions option = new ODataQueryOptions(context, message); + IODataQueryOptions option = new ODataQueryOptions(context, message); ODataValidationSettings settings = new ODataValidationSettings() { AllowedQueryOptions = AllowedQueryOptions.OrderBy @@ -881,7 +881,7 @@ public void Querying_Primitive_Collections(IQueryable queryable, string query, o { var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + query); ODataQueryContext context = new ODataQueryContext(EdmCoreModel.Instance, queryable.ElementType); - ODataQueryOptions options = new ODataQueryOptions(context, request); + IODataQueryOptions options = new ODataQueryOptions(context, request); queryable = options.ApplyTo(queryable); @@ -917,7 +917,7 @@ public void ODataQueryOptions_IgnoresUnknownOperatorStartingWithDollar() { var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/?$filter=$it eq 6&$unknown=value"); ODataQueryContext context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int)); - ODataQueryOptions options = new ODataQueryOptions(context, request); + IODataQueryOptions options = new ODataQueryOptions(context, request); var queryable = options.ApplyTo(Enumerable.Range(0, 10).AsQueryable()); @@ -932,7 +932,7 @@ public void ApplyTo_Entity_ThrowsArgumentNull_Entity() var message = RequestFactory.Create(); ODataQueryContext context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int)); - ODataQueryOptions queryOptions = new ODataQueryOptions(context, message); + IODataQueryOptions queryOptions = new ODataQueryOptions(context, message); ExceptionAssert.ThrowsArgumentNull( () => queryOptions.ApplyTo(entity: null, querySettings: new ODataQuerySettings()), @@ -963,7 +963,7 @@ public void ApplyTo_Entity_ThrowsArgumentNull_QuerySettings() var message = RequestFactory.Create(); ODataQueryContext context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int)); - ODataQueryOptions queryOptions = new ODataQueryOptions(context, message); + IODataQueryOptions queryOptions = new ODataQueryOptions(context, message); ExceptionAssert.ThrowsArgumentNull( () => queryOptions.ApplyTo(entity: 42, querySettings: null), @@ -982,7 +982,7 @@ public void ApplyTo_Entity_ThrowsInvalidOperation_IfNonSelectExpand(string param model.Model.SetAnnotationValue(model.Customer, new ClrTypeAnnotation(typeof(Customer))); var request = RequestFactory.Create(HttpMethod.Get, "http://localhost?" + parameter); ODataQueryContext context = new ODataQueryContext(model.Model, typeof(Customer)); - ODataQueryOptions queryOptions = new ODataQueryOptions(context, request); + IODataQueryOptions queryOptions = new ODataQueryOptions(context, request); ExceptionAssert.Throws( () => queryOptions.ApplyTo(42, new ODataQuerySettings()), @@ -999,7 +999,7 @@ public void ApplyTo_Entity_DoesnotApply_IfSetApplied(string queryOption, Allowed var builder = ODataConventionModelBuilderFactory.Create(); builder.EntitySet("Customers"); ODataQueryContext context = new ODataQueryContext(builder.GetEdmModel(), typeof(Customer)); - ODataQueryOptions options = new ODataQueryOptions(context, request); + IODataQueryOptions options = new ODataQueryOptions(context, request); Customer customer = new Customer { CustomerId = 1, @@ -1031,7 +1031,7 @@ public void ApplyTo_DoesnotApply_IfSetApplied(string queryOption, AllowedQueryOp var builder = ODataConventionModelBuilderFactory.Create(); builder.EntitySet("Customers"); ODataQueryContext context = new ODataQueryContext(builder.GetEdmModel(), typeof(Customer)); - ODataQueryOptions options = new ODataQueryOptions(context, request); + IODataQueryOptions options = new ODataQueryOptions(context, request); IQueryable customers = Enumerable.Range(1, 10).Select( i => new Customer @@ -1080,7 +1080,7 @@ public void ODataQueryOptions_WithUnTypedContext_CanBeBuilt() "http://localhost/?$filter=Id eq 42&$orderby=Id&$skip=42&$top=42&$count=true&$select=Id&$expand=Orders"); // Act - ODataQueryOptions queryOptions = new ODataQueryOptions(context, request); + IODataQueryOptions queryOptions = new ODataQueryOptions(context, request); // Assert Assert.NotNull(queryOptions.Filter); diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/SelectExpandQueryOptionTest.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/SelectExpandQueryOptionTest.cs index 5c34fb2258..2561d2b276 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/SelectExpandQueryOptionTest.cs +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/SelectExpandQueryOptionTest.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net.Http; using Microsoft.AspNet.OData.Builder; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNet.OData.Test.Abstraction; using Microsoft.AspNet.OData.Test.Common; @@ -682,7 +683,7 @@ public void ProcessLevelsCorrectly_WithAutoExpand(string url) model, model.FindDeclaredType("Microsoft.AspNet.OData.Test.Common.Models.AutoExpandCustomer")); var request = RequestFactory.Create(HttpMethod.Get, url); - var queryOption = new ODataQueryOptions(context, request); + ODataQueryOptions queryOption = new ODataQueryOptions(context, request); queryOption.AddAutoSelectExpandProperties(); var selectExpand = queryOption.SelectExpand; diff --git a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/Validators/ODataQueryValidatorTest.cs b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/Validators/ODataQueryValidatorTest.cs index c7f0a879f7..62691e1f39 100644 --- a/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/Validators/ODataQueryValidatorTest.cs +++ b/test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/Validators/ODataQueryValidatorTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; +using Microsoft.AspNet.OData.Interfaces; using Microsoft.AspNet.OData.Query; using Microsoft.AspNet.OData.Query.Validators; using Microsoft.AspNet.OData.Test.Abstraction; @@ -114,7 +115,7 @@ public void AllowedQueryOptions_SucceedIfAllowed(AllowedQueryOptions allow, stri { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?$" + query); - ODataQueryOptions option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); ODataValidationSettings settings = new ODataValidationSettings() { AllowedQueryOptions = allow, @@ -132,7 +133,7 @@ public void AllowedQueryOptions_ThrowIfNotAllowed(AllowedQueryOptions exclude, s { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + query); - var option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); var expectedMessage = string.Format( "Query option '{0}' is not allowed. " + "To allow it, set the 'AllowedQueryOptions' property on EnableQueryAttribute or QueryValidationSettings.", @@ -153,7 +154,7 @@ public void AllowedQueryOptions_ThrowIfNoneAllowed(AllowedQueryOptions unused, s { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + query); - var option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); var expectedMessage = string.Format( "Query option '{0}' is not allowed. " + "To allow it, set the 'AllowedQueryOptions' property on EnableQueryAttribute or QueryValidationSettings.", @@ -174,7 +175,7 @@ public void SupportedQueryOptions_SucceedIfGroupAllowed(AllowedQueryOptions unus { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?$" + query); - ODataQueryOptions option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); ODataValidationSettings settings = new ODataValidationSettings() { AllowedQueryOptions = AllowedQueryOptions.Supported, @@ -192,7 +193,7 @@ public void SupportedQueryOptions_ThrowIfGroupNotAllowed(AllowedQueryOptions unu { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + query); - var option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); var expectedMessage = string.Format( "Query option '{0}' is not allowed. " + "To allow it, set the 'AllowedQueryOptions' property on EnableQueryAttribute or QueryValidationSettings.", @@ -213,7 +214,7 @@ public void UnsupportedQueryOptions_SucceedIfGroupAllowed(AllowedQueryOptions un { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?$" + query); - ODataQueryOptions option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); ODataValidationSettings settings = new ODataValidationSettings() { AllowedQueryOptions = AllowedQueryOptions.All & ~AllowedQueryOptions.Supported, @@ -231,7 +232,7 @@ public void UnsupportedQueryOptions_ThrowIfGroupNotAllowed(AllowedQueryOptions u { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?" + query); - var option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); var expectedMessage = string.Format( "Query option '{0}' is not allowed. " + "To allow it, set the 'AllowedQueryOptions' property on EnableQueryAttribute or QueryValidationSettings.", @@ -251,7 +252,7 @@ public void Validate_ValidatesSelectExpandQueryOption_IfItIsNotNull() { // Arrange var message = RequestFactory.Create(HttpMethod.Get, "http://localhost/?$expand=Contacts/Contacts"); - ODataQueryOptions option = new ODataQueryOptions(_context, message); + IODataQueryOptions option = new ODataQueryOptions(_context, message); Mock selectExpandValidator = new Mock(new DefaultQuerySettings()); option.SelectExpand.Validator = selectExpandValidator.Object; diff --git a/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore.OData.PublicApi.bsl b/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore.OData.PublicApi.bsl index 4c24b0e99f..78f5e8a719 100644 --- a/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore.OData.PublicApi.bsl +++ b/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore.OData.PublicApi.bsl @@ -437,12 +437,12 @@ public class Microsoft.AspNet.OData.EnableQueryAttribute : Microsoft.AspNetCore. int MaxTop { public get; public set; } int PageSize { public get; public set; } - public virtual System.Linq.IQueryable ApplyQuery (System.Linq.IQueryable queryable, ODataQueryOptions queryOptions) - public virtual object ApplyQuery (object entity, ODataQueryOptions queryOptions) + public virtual System.Linq.IQueryable ApplyQuery (System.Linq.IQueryable queryable, IODataQueryOptions queryOptions) + public virtual object ApplyQuery (object entity, IODataQueryOptions queryOptions) public static Microsoft.AspNetCore.Mvc.SerializableError CreateErrorResponse (string message, params System.Exception exception) public virtual Microsoft.OData.Edm.IEdmModel GetModel (System.Type elementClrType, Microsoft.AspNetCore.Http.HttpRequest request, Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor actionDescriptor) public virtual void OnActionExecuted (Microsoft.AspNetCore.Mvc.Filters.ActionExecutedContext actionExecutedContext) - public virtual void ValidateQuery (Microsoft.AspNetCore.Http.HttpRequest request, ODataQueryOptions queryOptions) + public virtual void ValidateQuery (Microsoft.AspNetCore.Http.HttpRequest request, IODataQueryOptions queryOptions) } [ @@ -2377,6 +2377,10 @@ public interface Microsoft.AspNet.OData.Interfaces.IODataFeature { Microsoft.AspNetCore.Mvc.IUrlHelper UrlHelper { public abstract get; public abstract set; } } +[ +NonValidatingParameterBindingAttribute(), +ODataQueryParameterBindingAttribute(), +] public interface Microsoft.AspNet.OData.Interfaces.IODataQueryOptions { ApplyQueryOption Apply { public abstract get; } ODataQueryContext Context { public abstract get; } @@ -2403,6 +2407,9 @@ public interface Microsoft.AspNet.OData.Interfaces.IODataQueryOptions { void Validate (ODataValidationSettings validationSettings) } +[ +ODataQueryParameterBindingAttribute(), +] public interface Microsoft.AspNet.OData.Interfaces.IODataQueryOptions`1 : IODataQueryOptions { ETag`1 IfMatch { public abstract get; } ETag`1 IfNoneMatch { public abstract get; } @@ -2835,13 +2842,13 @@ public class Microsoft.AspNet.OData.Query.SkipTokenQueryOption { public SkipTokenQueryOption (string rawValue, ODataQueryContext context, Microsoft.OData.UriParser.ODataQueryOptionParser queryOptionParser) ODataQueryContext Context { public get; } - ODataQueryOptions QueryOptions { public get; } + IODataQueryOptions QueryOptions { public get; } ODataQuerySettings QuerySettings { public get; } string RawValue { public get; } SkipTokenQueryValidator Validator { public get; } - public virtual IQueryable`1 ApplyTo (IQueryable`1 query, ODataQuerySettings querySettings, ODataQueryOptions queryOptions) - public virtual System.Linq.IQueryable ApplyTo (System.Linq.IQueryable query, ODataQuerySettings querySettings, ODataQueryOptions queryOptions) + public virtual IQueryable`1 ApplyTo (IQueryable`1 query, ODataQuerySettings querySettings, IODataQueryOptions queryOptions) + public virtual System.Linq.IQueryable ApplyTo (System.Linq.IQueryable query, ODataQuerySettings querySettings, IODataQueryOptions queryOptions) public void Validate (ODataValidationSettings validationSettings) } @@ -3536,7 +3543,7 @@ public class Microsoft.AspNet.OData.Formatter.Serialization.ODataSerializerConte Microsoft.OData.Edm.IEdmNavigationProperty NavigationProperty { public get; } Microsoft.OData.Edm.IEdmNavigationSource NavigationSource { public get; public set; } ODataPath Path { public get; public set; } - ODataQueryOptions QueryOptions { public get; } + IODataQueryOptions QueryOptions { public get; } Microsoft.AspNetCore.Http.HttpRequest Request { public get; public set; } string RootElementName { public get; public set; } Microsoft.OData.UriParser.SelectExpandClause SelectExpandClause { public get; public set; } @@ -3667,7 +3674,7 @@ public class Microsoft.AspNet.OData.Query.Validators.FilterQueryValidator { public class Microsoft.AspNet.OData.Query.Validators.ODataQueryValidator { public ODataQueryValidator () - public virtual void Validate (ODataQueryOptions options, ODataValidationSettings validationSettings) + public virtual void Validate (IODataQueryOptions options, ODataValidationSettings validationSettings) } public class Microsoft.AspNet.OData.Query.Validators.OrderByQueryValidator { diff --git a/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore3x.OData.PublicApi.bsl b/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore3x.OData.PublicApi.bsl index 8e59087d3e..7bb2331b17 100644 --- a/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore3x.OData.PublicApi.bsl +++ b/test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore3x.OData.PublicApi.bsl @@ -437,12 +437,12 @@ public class Microsoft.AspNet.OData.EnableQueryAttribute : Microsoft.AspNetCore. int MaxTop { public get; public set; } int PageSize { public get; public set; } - public virtual System.Linq.IQueryable ApplyQuery (System.Linq.IQueryable queryable, ODataQueryOptions queryOptions) - public virtual object ApplyQuery (object entity, ODataQueryOptions queryOptions) + public virtual System.Linq.IQueryable ApplyQuery (System.Linq.IQueryable queryable, IODataQueryOptions queryOptions) + public virtual object ApplyQuery (object entity, IODataQueryOptions queryOptions) public static Microsoft.AspNetCore.Mvc.SerializableError CreateErrorResponse (string message, params System.Exception exception) public virtual Microsoft.OData.Edm.IEdmModel GetModel (System.Type elementClrType, Microsoft.AspNetCore.Http.HttpRequest request, Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor actionDescriptor) public virtual void OnActionExecuted (Microsoft.AspNetCore.Mvc.Filters.ActionExecutedContext actionExecutedContext) - public virtual void ValidateQuery (Microsoft.AspNetCore.Http.HttpRequest request, ODataQueryOptions queryOptions) + public virtual void ValidateQuery (Microsoft.AspNetCore.Http.HttpRequest request, IODataQueryOptions queryOptions) } [ @@ -2548,6 +2548,10 @@ public interface Microsoft.AspNet.OData.Interfaces.IODataFeature { Microsoft.AspNetCore.Mvc.IUrlHelper UrlHelper { public abstract get; public abstract set; } } +[ +NonValidatingParameterBindingAttribute(), +ODataQueryParameterBindingAttribute(), +] public interface Microsoft.AspNet.OData.Interfaces.IODataQueryOptions { ApplyQueryOption Apply { public abstract get; } ODataQueryContext Context { public abstract get; } @@ -2574,6 +2578,9 @@ public interface Microsoft.AspNet.OData.Interfaces.IODataQueryOptions { void Validate (ODataValidationSettings validationSettings) } +[ +ODataQueryParameterBindingAttribute(), +] public interface Microsoft.AspNet.OData.Interfaces.IODataQueryOptions`1 : IODataQueryOptions { ETag`1 IfMatch { public abstract get; } ETag`1 IfNoneMatch { public abstract get; } @@ -3006,13 +3013,13 @@ public class Microsoft.AspNet.OData.Query.SkipTokenQueryOption { public SkipTokenQueryOption (string rawValue, ODataQueryContext context, Microsoft.OData.UriParser.ODataQueryOptionParser queryOptionParser) ODataQueryContext Context { public get; } - ODataQueryOptions QueryOptions { public get; } + IODataQueryOptions QueryOptions { public get; } ODataQuerySettings QuerySettings { public get; } string RawValue { public get; } SkipTokenQueryValidator Validator { public get; } - public virtual IQueryable`1 ApplyTo (IQueryable`1 query, ODataQuerySettings querySettings, ODataQueryOptions queryOptions) - public virtual System.Linq.IQueryable ApplyTo (System.Linq.IQueryable query, ODataQuerySettings querySettings, ODataQueryOptions queryOptions) + public virtual IQueryable`1 ApplyTo (IQueryable`1 query, ODataQuerySettings querySettings, IODataQueryOptions queryOptions) + public virtual System.Linq.IQueryable ApplyTo (System.Linq.IQueryable query, ODataQuerySettings querySettings, IODataQueryOptions queryOptions) public void Validate (ODataValidationSettings validationSettings) } @@ -3707,7 +3714,7 @@ public class Microsoft.AspNet.OData.Formatter.Serialization.ODataSerializerConte Microsoft.OData.Edm.IEdmNavigationProperty NavigationProperty { public get; } Microsoft.OData.Edm.IEdmNavigationSource NavigationSource { public get; public set; } ODataPath Path { public get; public set; } - ODataQueryOptions QueryOptions { public get; } + IODataQueryOptions QueryOptions { public get; } Microsoft.AspNetCore.Http.HttpRequest Request { public get; public set; } string RootElementName { public get; public set; } Microsoft.OData.UriParser.SelectExpandClause SelectExpandClause { public get; public set; } @@ -3838,7 +3845,7 @@ public class Microsoft.AspNet.OData.Query.Validators.FilterQueryValidator { public class Microsoft.AspNet.OData.Query.Validators.ODataQueryValidator { public ODataQueryValidator () - public virtual void Validate (ODataQueryOptions options, ODataValidationSettings validationSettings) + public virtual void Validate (IODataQueryOptions options, ODataValidationSettings validationSettings) } public class Microsoft.AspNet.OData.Query.Validators.OrderByQueryValidator {