-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support for custom query option implementation with a simple extension handler #617
base: release-8.x
Are you sure you want to change the base?
Changes from 3 commits
88c0f0b
c40a69f
4ae690d
9254ccf
92852bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
//----------------------------------------------------------------------------- | ||
// <copyright file="ExampleQueryOptionsBindingExtension.cs" company=".NET Foundation"> | ||
// Copyright (c) .NET Foundation and Contributors. All rights reserved. | ||
// See License.txt in the project root for license information. | ||
// </copyright> | ||
//------------------------------------------------------------------------------ | ||
|
||
using Microsoft.AspNetCore.OData.Query; | ||
using Microsoft.AspNetCore.OData.Query.Extension; | ||
using System.Linq; | ||
|
||
namespace ODataRoutingSample | ||
{ | ||
public class ExampleQueryOptionsBindingExtension : IODataQueryOptionsBindingExtension | ||
{ | ||
public IQueryable ApplyTo(IQueryable query, ODataQueryOptions queryOptions, ODataQuerySettings querySettings) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are these params used for ? |
||
{ | ||
//Do something here | ||
return query; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,11 +5,14 @@ | |
// </copyright> | ||
//------------------------------------------------------------------------------ | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.ApplicationModels; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.OData.Query; | ||
using Microsoft.AspNetCore.OData.Query.Extension; | ||
using Microsoft.AspNetCore.OData.Routing; | ||
using Microsoft.AspNetCore.OData.Routing.Parser; | ||
using Microsoft.AspNetCore.OData.Routing.Template; | ||
|
@@ -105,5 +108,52 @@ internal static IServiceCollection AddODataCore(this IServiceCollection services | |
|
||
return services; | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="IODataQueryOptionsBindingExtension"/> to a service collection. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> | ||
/// <param name="extension">The <see cref="IODataQueryOptionsBindingExtension"/> to add to the service collection.</param> | ||
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns> | ||
public static IServiceCollection AddDataQueryOptionsBindingExtension(this IServiceCollection services, IODataQueryOptionsBindingExtension extension) | ||
{ | ||
if (services == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(services)); | ||
} | ||
|
||
if (services == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(extension)); | ||
} | ||
|
||
services.AddSingleton<IODataQueryOptionsBindingExtension>(extension); | ||
return services; | ||
} | ||
|
||
/// <summary> | ||
/// Adds multiple <see cref="IODataQueryOptionsBindingExtension"/> to a service collection. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> | ||
/// <param name="extensions">The <see cref="IODataQueryOptionsBindingExtension"/> to add to the service collection.</param> | ||
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns> | ||
public static IServiceCollection AddMultipleDataQueryOptionsBindingExtension(this IServiceCollection services, Action<IList<IODataQueryOptionsBindingExtension>> extensions) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think I understand why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I like it more this way because I think it looks better in the configuration :). But it can also be changed if you don't like this approach.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure yet if I'm nitpicking or not :), but I think then wouldn't the delegate be
In fact, though, before I waste too much of your time, @xuzhg are you alright with the structure of this change? If so, I'll go ahead and start reviewing more, but I want to make sure we are heading in the right direction first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @corranrogue9 Your solution is also fine, both should work :) |
||
{ | ||
if (services == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(services)); | ||
} | ||
|
||
if (extensions == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(extensions)); | ||
} | ||
|
||
IList<IODataQueryOptionsBindingExtension> extensionResult = new List<IODataQueryOptionsBindingExtension>(); | ||
extensions.Invoke(extensionResult); | ||
services.AddSingleton<IODataQueryOptionsBindingExtension>(new MultipleODataQueryOptionsBindingExtension(extensionResult)); | ||
|
||
return services; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//----------------------------------------------------------------------------- | ||
// <copyright file="IODataQueryOptionsBindingExtension.cs" company=".NET Foundation"> | ||
// Copyright (c) .NET Foundation and Contributors. All rights reserved. | ||
// See License.txt in the project root for license information. | ||
// </copyright> | ||
//------------------------------------------------------------------------------ | ||
|
||
using System.Linq; | ||
|
||
namespace Microsoft.AspNetCore.OData.Query.Extension | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please add some tests for this new feature? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added some tests. |
||
{ | ||
|
||
/// <summary> | ||
/// This interface allows to extend the <see cref="ODataQueryOptions.ApplyTo(object, ODataQuerySettings)"/> method | ||
/// and apply custom query features. | ||
/// </summary> | ||
public interface IODataQueryOptionsBindingExtension | ||
{ | ||
|
||
/// <summary> | ||
/// Apply a custom query to the given IQueryable. | ||
/// </summary> | ||
/// <param name="query">The original <see cref="IQueryable"/>.</param> | ||
/// <param name="queryOptions">The <see cref="ODataQueryOptions"/> object that is executing this method.</param> | ||
/// <param name="querySettings">The settings to use in query composition.</param> | ||
/// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns> | ||
public IQueryable ApplyTo(IQueryable query, ODataQueryOptions queryOptions, ODataQuerySettings querySettings); | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
//----------------------------------------------------------------------------- | ||
// <copyright file="MultipleODataQueryOptionsBindingExtension.cs" company=".NET Foundation"> | ||
// Copyright (c) .NET Foundation and Contributors. All rights reserved. | ||
// See License.txt in the project root for license information. | ||
// </copyright> | ||
//------------------------------------------------------------------------------ | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Microsoft.AspNetCore.OData.Query.Extension | ||
{ | ||
|
||
/// <summary> | ||
/// This class allows to use multiple <see cref="IODataQueryOptionsBindingExtension"/> extenion interfaces. | ||
/// </summary> | ||
public class MultipleODataQueryOptionsBindingExtension : IODataQueryOptionsBindingExtension | ||
{ | ||
|
||
private readonly IList<IODataQueryOptionsBindingExtension> _extensions; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="MultipleODataQueryOptionsBindingExtension"/> class | ||
/// with a list of extension interfaces. | ||
/// </summary> | ||
/// <param name="extensions">A list of query extensions to apply.</param> | ||
public MultipleODataQueryOptionsBindingExtension(IList<IODataQueryOptionsBindingExtension> extensions) | ||
{ | ||
_extensions = extensions; | ||
} | ||
|
||
/// <summary> | ||
/// Apply multiple custom queries to the given IQueryable. | ||
/// </summary> | ||
/// <param name="query">The original <see cref="IQueryable"/>.</param> | ||
/// <param name="queryOptions">The <see cref="ODataQueryOptions"/> object that is executing this method.</param> | ||
/// <param name="querySettings">The settings to use in query composition.</param> | ||
/// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns> | ||
public IQueryable ApplyTo(IQueryable query, ODataQueryOptions queryOptions, ODataQuerySettings querySettings) | ||
{ | ||
if (query == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(query)); | ||
} | ||
|
||
if (queryOptions == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(queryOptions)); | ||
} | ||
|
||
if (querySettings == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(querySettings)); | ||
} | ||
|
||
IQueryable result = query; | ||
foreach (var extension in _extensions) | ||
{ | ||
result = extension.ApplyTo(query, queryOptions, querySettings); | ||
} | ||
return result; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the intention here to return the last result and ignore the rest ? |
||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please provide some documentation for Public classes, functions and methods.