Skip to content
This repository was archived by the owner on Dec 29, 2020. It is now read-only.

Controllers

Trevor Pilley edited this page Apr 2, 2020 · 10 revisions

Assume the following simple Product class which we want to query using OData 4.0:

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public DateTime ReleaseDate { get; set; }
}

The MicroLite WebApi OData Extension adds support for OData Queries by providing the MicroLiteODataApiController<TEntity, TEntityKey>.

If you want to enable it, simply derive your controller from the MicroLiteODataApiController<TEntity, TEntityKey> class:

[RoutePrefix("odata")]
public class ProductODataController : MicroLiteODataApiController<Product, int>
{
}

Note that it is required to use the route prefix 'odata' over 'api' for OData controllers.

Collection Count

This will allow you to call GET http://myservice/odata/Products/$count which will return the raw integer value of the total number of Products. It is opt-in, add the following method to any controller which you want /$count for (this is different to the $count=true in the OData Query Options below).

[HttpGet, Route("Products/$count")]
public Task<IHttpActionResult> Count()
    => this.GetCountResponseAsync();

Example Response:

125

Single entity by ID

This will allow you to call GET http://myservice/odata/Products(1) which will return the entity values (or a 404 if no record exists with the requested ID).

[HttpGet, Route("Products({id:int})")]
public Task<IHttpActionResult> Get(int id)
    => this.GetEntityResponseAsync(id);

Example Response:

{ "ProductId": 1, "Name": "Milk", "Price": 1.15, "ReleaseDate": "2012-04-15T00:00:00.0" }

Single entity property

This will allow you to call GET http://myservice/odata/Products(1)/Price which will return the entity property (or a 404 if no record exists with the requested ID, or a 400 if the property name does not exist).

[HttpGet, Route("Products({id:int})/{propertyName}")]
public Task<IHttpActionResult> GetProperty(int id, string propertyName)
    => this.GetEntityPropertyResponseAsync(id, propertyName);

Example Response:

{ "value": 1.15 }

Single entity property value

This will allow you to call GET http://myservice/odata/Products(1)/Price/$value which will return the property value (or a 404 if no record exists with the requested ID, or a 400 if the property name does not exist).

[HttpGet, Route("Products({id:int})/{propertyName}/$value")]
public Task<HttpResponseMessage> GetPropertyValue(int id, string propertyName) => this.GetEntityPropertyValueResponseAsync(id, propertyName);

Example Response:

1.15

Query Support

Add the following method to your controller:

[HttpGet, Route("Products")] // The Route should match the entity set name defined in the Entity Data Model
public Task<IHttpActionResult> Get(ODataQueryOptions queryOptions)
    => this.GetEntityResponseAsync(queryOptions);

The following query options are currently supported:

  • $select
  • $filter
  • $skip
  • $top
  • $orderby
  • $count
  • $format

$select

$select – this allows you to limit which properties are returned in the query, if no $select value is specified, all properties will be included. Property names must be cased correctly.

URI: /odata/products?$select=ProductId,Name,Price

would return results such as:

[{ "ProductId": 1, "Name": "Milk", "Price": 1.15 }, { "ProductId": 2, "Name": "Bread", "Price": 0.65 } ]

This means that the result set won’t contain properties that you have not specified so you won’t get default values returned in property values which haven’t been retrieved from the database and makes the response payload smaller.

$filter

$filter - this allows you to constrain the results returned based upon specified predicates, if no $filter value is specified, all results will be returned (up to the maximum supported by the controller).

Return all products released after 1st Jan 2010:

URI /odata/products?$filter=Released gt 2010-01-01

MicroLite.Extensions.WebApi.OData currently supports the following filter options:

Logical Operators
  • and
  • eq
  • ge
  • gt
  • has (from 7.1.0)
  • le
  • lt
  • ne
  • not
  • or
Arithmetic Operators
  • add
  • div
  • mod
  • mul
  • sub

Grouping Operators

  • () Precedence Grouping
String Functions
  • concat (from 7.1.0)
  • contains
  • endswith
  • indexof
  • length
  • startswith
  • substring
  • tolower
  • toupper
  • trim
Date Functions
  • date
  • day
  • fractionalseconds
  • hour
  • maxdatetime
  • mindatetime
  • minute
  • month
  • now (from 7.1.0)
  • second
  • totaloffsetminutes
  • year
Math Functions
  • ceiling
  • floor
  • round
Type Functions
  • cast
  • isof

$skip/$top

$skip and $top can be used to constrain the number of results returned to implement paging:

URI /odata/products?$skip=50&$top=50

$orderby

$orderby – this allows you to specify how the results are ordered in the result set.

Sort by Name ascending and then within each Name, ReleaseDate descending:

URI /odata/products?$orderby=Name,ReleaseDate desc

If not specified, the order will default to ascending. If specified, the order must be asc or desc

$count

$count – allows you to ask the results to be returned along with a total count of the results. If not specified, no count will be used.

Include in the results a property called count which contains the total number of results:

URI /odata/products?$count=true

Do not include a count in the results – this is the default behaviour if not specified:

URI /odata/products?$count=false

The query options can be combined to filter results however you like, BUT each option may only appear once.

$format

$format – allows you to override the format the data should be returned in regardless of the value in the content-type HTTP header:

regardless of the content-type header value, return the results in JSON:

URI /odata/products?$format=json

Validating Queries

You can validate the types of query which can be executed against a controller by specifying the Validation

They can be specified exclusive of each other and the $top value can be validated by the ValidationSettings in the controller.

public ProductODataController()
{
    // MaxTop will default to 50 if not otherwise specified & will be used to limit the max value 
    // allowed in $top or constrain the results if no $top is specified in the OData query.
    this.ValidationSettings.MaxTop = 100;
}

You can also specify the AllowedFunctions and AllowedQueryOptions. By default, all supported functions and query options are allowed.

Clone this wiki locally