AutoQueryable
AutoQueryable add auto querying functionality like OData on top of IQueryable with best url practices to Asp.Net & Asp.Net Core
Install / Use
/learn @trenoncourt/AutoQueryableREADME
AutoQueryable ·

AutoQueryable add auto querying functionality like OData on top of IQueryable with best url practices. It help you to make requests like http://baseurl/api/products?nameContains=frame&color=red,black with no effort.
With this url: /products?select=productId,name,color,productCategory.name,salesOrderDetail,salesOrderDetail.product
You will get result like:
[
{
"productId": 1,
"name": "Product 0",
"color": "red",
"productCategory": {
"name": "red"
},
"salesOrderDetail": [
{
"product": {
"productId": 1,
"name": "Product 0",
"productNumber": "24bb9446-d540-4513-a3c6-be4323984112",
...
"modifiedDate": "0001-01-01T00:00:00",
"salesOrderDetail": []
},
"salesOrderId": 0,
"salesOrderDetailId": 1,
...
},
...
]
},
...
]
Installing / Getting started
| Package | NuGet | |
|----------------|-------------------------------------------------------------------------------------------|-|
| Install-Package AutoQueryable | | Install without filters |
| AutoQueryable.AspNetCore.Filter |
| Install for AspNet Core |
| AutoQueryable.AspNetCore.Swagger |
| Install for AspNet Core |
| AutoQueryable.Extensions.DependencyInjection |
| Install for AspNet Core |
| AutoQueryable.AspNet.Filter |
| Install for Web api 2 |
| AutoQueryable.AspNet |
| Install for Web api 2 |
| AutoQueryable.Extensions.Autofac |
| Install for Web api 2 |
| AutoQueryable.Nancy.Filter (old version) |
| Install for Nancy |
Other web framework? You could made your own attribute, see Use AutoQueryable without attribute section.
Getting started
1. DI configuration
For ASP.NET Core
Install the DI package: AutoQueryable.Extensions.DependencyInjection and register AutoQueryable dependencies with your favorite DI framework
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAutoQueryable();
}
For ASP.NET Framework
Install the DI package: AutoQueryable.Extensions.Autofac and register AutoQueryable dependencies
protected void Application_Start()
{
var builder = new ContainerBuilder();
...
builder.RegisterAutoQueryable();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(builder.Build())
}
2. Default settings configuration
you can configure the default AutoQueryable settings. For example get only 10 results :
For ASP.NET Core
services.AddAutoQueryable(settings => settings.DefaultToTake = 10)
For ASP.NET Framework
builder.RegisterAutoQueryable(settings => settings.DefaultToTake = 10);
3. Use AutoQueryable
Ensure your API actions are decorated with AutoQueryable attribute and let the magic begin.
[HttpGet, AutoQueryable]
public IQueryable<Product> Get([FromServices] MyDbContext dbContext)
{
return dbContext.Product;
}
AQ settings can be overriden in attribute too
[AutoQueryable(DefaultToTake = 50, UnselectableProperties = new [] {"Id", "Password"})]
...
Note that you can use AQ without attribute, see Use AutoQueryable without attribute section
Api URL usage
- Selectable columns: /products?select=name,color,toto
- Top/Take, Skip: /products?take=5&skip=5
- First, Last: /products?first=true
- OrderBy, OrderByDesc: /products?orderby=price,id
- Wrap with: /products?wrapwith=count,total-count,next-link
- Filtering: /products?nameContains=frame&color=red,black
- Paging: /products?page=2&pagesize=10
And / Or management
- In a single filter, properties are managed with OR, eg
prop1=a,b,c - If you want single filter with AND you need to add the same filter, eg
prop1=a&prop1=b&prop1=c - If multiple filters are provided, there are managed with AND, eg
prop1=a&prop2=a&prop3Contains=b - If you want multiple filters with OR, you must provide all filters before the =, eg
prop1StartsWith,prop2:i,prop3Contains:i=a,b,c
Selection
- Select all properties of level zero without relations: /products?select=_
- Select all properties of level zero with relations: /products?select=*
- Select an object with all its value types: /products?select=productcategory
- Select an object with all its values including navigation properties on the first level: /products?select=productcategory.*
Projection
You can use projection in select & filters clauses with navigation properties (objects or collection of object)
- Select projection: /products?select=name,color,toto,productcategory.name
- Filter projection: /products?salesorderdetail.product.productid=1
Dto projection
You can still use dto projection and query over your dto with defined type:
[HttpGet]
[AutoQueryable]
public IQueryable Get([FromServices] AdventureWorksContext adventureWorksContext)
{
return adventureWorksContext.Product.Select(p => new ProductProjection
{
Name = p.Name,
ProductColor = p.Color,
FinalPrice = p.price
});
}
Or anonymous type:
[HttpGet]
[AutoQueryable]
public IQueryable Get([FromServices] AdventureWorksContext adventureWorksContext)
{
return adventureWorksContext.Product.Select(p => new
{
p.Name,
p.Color,
FinalPrice = p.Price
});
}
Unselectable properties
If you want some properties to be unselectable (eg: Id, Password, ...)
[Route("api/[controller]")]
public class UsersController : Controller
{
[HttpGet]
[AutoQueryable(UnselectableProperties = new []{ "Password", "Id" })]
public IQueryable<User> Get([FromServices] myDbContext dbContext)
{
return dbContext.User;
}
}
Note that Dto projection is the best way to limit selectable properties
Existing filters
By default filters are separated by AND (eg: color=red&color=black is translated by color == red AND color == black)
In a filter, comma separator is used for OR (eg: color=red,black is translated by color == red OR black)
- Equals '=': /products?color=red,black
- Not Equals '!=': /products?color!=green,blue
- Less Than, Greater Than '<', '>': /products?productCount<5
- Less Than or Equals, Greater Than or equals '<=' /products?productCount<=5
- Contains 'contains': /products?colorContains=bla,ed
- StartsWith, EndsWith 'startswith', 'endswith': /products?colorStartsWith=bla,re
String filters have a negate (NOT) variant:
- NotContains 'notcontains': /products?colorContains!=bla,ed
- NotStartsWith, NotEndsWith 'notstartswith', 'notendswith': /products?colorStartsWith!=bla,ed
Filter aliases are not case sensitive:
- Contains 'contains': /products?colorcontains=bla,ed
*Note that filters works with primitive types, string, d
