![]() |
VOOZH | about |
dotnet add package ODataQuery --version 2.1.1
NuGet\Install-Package ODataQuery -Version 2.1.1
<PackageReference Include="ODataQuery" Version="2.1.1" />
<PackageVersion Include="ODataQuery" Version="2.1.1" />Directory.Packages.props
<PackageReference Include="ODataQuery" />Project file
paket add ODataQuery --version 2.1.1
#r "nuget: ODataQuery, 2.1.1"
#:package ODataQuery@2.1.1
#addin nuget:?package=ODataQuery&version=2.1.1Install as a Cake Addin
#tool nuget:?package=ODataQuery&version=2.1.1Install as a Cake Tool
This package enables server-side filtering, sorting and pagination of any IQueryable<T> using OData syntax and without needing an EDM model.
This is achieved simply by adding [ODataQueryable] to any such API.
Add a reference to Nuget package ODataQuery.
// Import this namespace
using ODataQuery;
[Route("api/version")]
public class VersionController
{
// Add attribute ODataQueryable
[HttpGet, ODataQueryable]
public IQueryable<Version> Get()
{
// Source data can be anything (most likely an EF query)...
var versions = new[] {
new Version(1, 0),
new Version(1, 1),
new Version(2, 0),
new Version(3, 0),
};
// ... as long as it's IQueryable<T>
return versions.AsQueryable();
}
}
Now you can filter, sort and paginate versions:
GET /api/version?$filter=major gt 2&$orderby=major desc
would return this response:
{
"value": [
{ "major": 3, "minor": 0 },
{ "major": 2, "minor": 0 }
]
}
ODataQueryable changes the shape of your response to a standard OData response:
{ "value": [...] } by default;{ "@odata.count": 42, "value": [...] } if you used the $count option.The goal of this project is to enable easy server-side processing of datagrids, lists and co. in web applications, while being secure by default
(e.g. you can't fetch the full DB through $expand, because it's not supported).
Currently it has the following limitations:
$filter, $search, $orderby, $skip, $top, $select and $count.That last point warrants an explanation.
You will get a ParseException if the query string is not correctly formatted and the message will indicate where it failed,
but the error message can often be unhelpful: e.g. mentioning a single expected character instead of a full token.
You will also get various exceptions if the query can be parsed but is semantically incorrect (properties that don't exist, type errors, invalid date literals).
In all cases this will likely result in a 500 Internal Error, although a 400 code (bad request) would be more appropriate.
With respect to error-friendliness, this API is not meant to be used to build public, open APIs.
Apply [ODataQueryable] to automatically apply OData query string to an IQueryable<T> result and return an OData response.
If the method throws, doesn't return a success code (2xx) or doesn't return an IQueryable<T> result then this attribute does nothing.
This package adds an extension method to IQueryable<T> to apply the query string manually in your code:
IQueryable<T> source;
// Does not apply $count
IQueryable<T> result = source.OData(HttpContext.Request.Query);
// Applies $count and return result in out parameter
int count;
IQueryable<T> result = source.OData(HttpContext.Request.Query, out count);
Two extension methods let you apply $filter or $orderby directly from a string:
IQueryable<T> source;
IQueryable<T> result = source.ODataFilter("amount gt 1000")
.ODataOrderBy("release desc,id");
This library follows OData conventions, with the following extensions:
DateTime is supported (OData only supports DateTimeOffset).
Literals without a timezone parse as DateTime, literals with a timezone as DateTimeOffset.
in operator can have an empty list on right hand side: x in ().
This is forbidden by OData grammar but it is accepted by this library and evaluates to false.
This library implements a subset of OData 4.0.1.
Only $filter, $orderby, $top, $skip and $count are supported.
Supported: Numeric types, DateOnly, DateTime, DateTimeOffset, bool, string, enums.
Literals:
'Marc''s house'-? [0-9]+ (. [0-9]+)?2019-07-22, 2019-07-22T14:15:00, and 2019-07-22T14:15:00+0200'red'.true, falsenullStarting with a letter or _, then followed by letters, digits and _.
Identifier are looked for in a case-insensitive way in model. So id eq 3 will match a property Id on the server.
Path to subproperties such as Address/City are not supported.
Comparison operators:
eq, ne, lt, le, gt, ge, inhasLogical operators:
and, or, notArithmetic operators:
add, sub, mul, div, divby, mod.Grouping operators:
()String functions:
contains, endswith, startswith, length, indexof, substring, tolower, toupper, trim, concatDate functions:
year, month, day, hour, minute, second, date.fractionalseconds, time, totaloffsetminutes, now, mindatetime, maxdatetime.Math functions:
round, floor, ceiling.Type functions:
cast, isof.Geo function:
geo.distance, geo.length, geo.intersects.Custom functions are supported.
They must be registered globally with ODataQueryableOptions.RegisterFunction() before using them. Registration takes three parameters:
string name: the name of the function as it appears in the query string. Following OData convention, it must include a namespace, e.g. my.function.Func<Expression[], Expression> mapper: a delegate that builds the resulting Expression from its arguments.params Type[] argTypes: an optional list of input argument types. When used, ODataQueryable will automatically add Convert expression nodes where required.
This is useful as conversion are commonly required, e.g. different exact number types, or nullable structs.Filter must evaluate to any boolean expression and is applied as Where.
Collection predicates such as any and all are not supported, neither are paths to sub-properties such as Address/City.
The semantics of what search does is up to the application: which fields? case-sensitive? starts, contains or exact match?
For this reason, the attribute ODataQueryable simply binds a $search query string to a search parameter (if any), so that you can apply the search yourself.
Sorting is a comma-separated list of expressions, optionnally followed by keywords asc and desc.
It is applied as OrderBy, ThenBy, respectively OrderByDescending, ThenByDescending.
Note: OData grammar doesn't allow spaces before or after commas in $orderby, neither does this library. So $orderby=name, id will throw.
Projecting only supports a list of plain identifiers.
It is applied as a Select that returns a lightweight IDictionary<string, object> that is meant to be serialized (it is not fully functional and most methods throw NotImplementedException).
If $count=true is in the query string, the response will have an additional @odata.count property set to the count of results just after applying filter, i.e. before applying $top, $skip, and $orderby.
It is applied as a call to Count (so 2 queries are executed).
Note: only the OData 4.0 $count option is supported. Previously it was $inline-count=allpages, which is not supported by this library.
Both supported as plain integers, applied as Take and Skip calls.
Note: before v1.1 this package looked for $take instead of $top which is not the OData standard.
For backward compatibility, $take is still accepted as a synonym of $top but it's usage is discouraged.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.1 | 12,460 | 11/19/2024 |
| 2.1.0 | 207 | 11/18/2024 |
| 2.0.0 | 3,389 | 6/19/2024 |
| 1.4.0 | 597 | 8/15/2023 |
| 1.3.0 | 213 | 8/14/2023 |
| 1.2.0 | 330 | 4/4/2023 |
| 1.1.0 | 866 | 7/27/2022 |
| 1.0.0 | 538 | 8/3/2021 |
| 0.5.0-pre | 401 | 1/6/2021 |
| 0.4.0-pre | 363 | 1/5/2021 |
| 0.3.0-pre | 422 | 12/2/2020 |
| 0.2.0-pre | 547 | 9/18/2019 |
| 0.1.0-pre | 557 | 7/22/2019 |