Tag Archives: WebApi

MicroLite OData update

The latest release of MicroLite.Extensions.WebApi (6.1) and Net.Http.WebApi.OData (3.1) now provide support for nearly the entire OData 3 spec that can be supported by MicroLite.

It is now possible to compare 2 properties:

$filter=FirstName eq LastName

And call nested functions:

$filter=concat(concat(City, ', '), Country) eq 'Berlin, Germany'

Decimal/Double and Single values don’t require .0 for whole values:

$filter=Price eq 5M can now be used as well as $filter=Price eq 5.0M

Method parameters no longer require a space after the comma:

$filter=endswith(CompanyName,'Futterkiste’) can now be used as well as
$filter=endswith(CompanyName, 'Futterkiste')

Literal strings (text wrapped in single quotes) can now contain a single quote by escaping it with another single quote:

$filter=LastName eq ‘O’’Brien’

Grouping is now supported in queries:

$filter=LastName eq 'Smith' and (Title eq 'Mr' or Title eq 'Mrs')

Without the grouping, the query would be translated as:

LastName = Smith and Title = Mr
Or
Title = Mrs

There is no concept of an “in list” in OData so a grouped set of “or”s is the way to achieve the same result.

endswith, startswith, and substringof now no longer require eq true at the end:

startswith(CompanyName,’Alfr’) is the same as startswith(CompanyName,’Alfr’) eq true

The not operator has also been implemented which means you can negate function calls:

not startswith(CompanyName,’Alfr’)

Upgrading to MicroLite 6.0

There are a few changes in MicroLite 6.0 and some of the extensions which you need to be aware of when updating from a previous version.

The .NET 4.5 build now contains an Async version of the session api (IAsyncSession and IAsyncReadOnlySession). If you are using a .NET 4.5 app, I suggest you update to make full use of the async version. The MVC and WebApi extensions already exclusively make use of it (see further below for more details).

Here’s the .NET 4.5 async version of each session method:

.NET 4.0 API .NET 4.5 API
Read API
Session.Fetch(SqlQuery) await Session.FetchAsync(SqlQuery)
Session.Paged(SqlQuery) await Session.PagedAsync(SqlQuery)
Session.Single(obj) await Session.SingleAsync(obj)
Session.Single(SqlQuery) await Session.SingleAsync(SqlQuery)
Write API
Session.Delete(obj) await Session.DeleteAsync(obj)
Session.Insert(obj) await Session.InsertAsync(obj)
Session.Update(obj) await Session.UpdateAsync(obj)
Session.Advanced.Delete(Type, obj) await Session.Advanced.DeleteAsync(Type, obj)
Session.Advanced.Execute(SqlQuery) await Session.Advanced.ExecuteAsync(SqlQuery)
Session.Advanced.ExecuteScalar(SqlQuery) await Session.Advanced.ExecuteScalarAsync(SqlQuery)
Session.Advanced.Update(ObjectDelta) await Session.Advanced.UpdateAsync(ObjectDelta)

Attribute Mapping

If you use the attribute based mapping, the attributes are now in the MicroLite.Mapping.Attributes namespace rather than MicroLite.Mapping.

DbEncryptedString

The DbEncryptedString class and associated classes has moved to the new MicroLite.Extensions.Cryptography project

SQL Builder

The Delete and Update Builder WhereEquals method has been replaced with Where().IsEqualTo() to align it with the Select Builder

MicroLite.Extensions.Mvc

Method signature needs to change from:

public ActionResult MethodName(args)

to

public async Task<ActionResult> MethodName(args)

MicroLite.Extensions.WebApi

Method signature needs to change from:

public HttpResponseMessage Get(int id)

to

public Task<HttpResponseMessage> Get(int id)

example:

public Task<HttpResponseMessage> Get(int id)
{
    return this.GetEntityResponseAsync(id);
}

WebApi OData filtering

In the previous post, we discussed the OData support in MicroLite.Extensions.WebApi 3.0.

When it comes to using $filter, we may want to restrict our results based upon properties which are data types other than a string.

OData dates and guids are specified as strings (quoted with single quotes) but allows the data type to prefix the value:

Dates should be specified in the yyyy-mm-dd format and optional include time by adding Thh:mm after dd. Dates in the Round Trip Date Format (“o” in C#) are also supported if you need to include higher precision and/or timezone information.

For a Date: $filter=Joined gt datetime'2010-01-01'
For a DateTime: $filter=Joined gt datetime'2013-10-23T10:00'
For a Guid: $filter=Identifier eq guid'D30648F9-6CAB-47AF-B010-53C8CD1CCB44'

Boolean values (true or false) are supported as unquoted literals:

$filter=Enabled eq true
$filter=Enabled eq false

To specify a decimal, use the M character after the value

$filter=Total gt 125.00M

To specify a double, use the D character after the value

$filter=Area gt 1512.1245D

To specify an integer, just specify a whole integer value

$filter=ItemCount eq 12

To specify a single, use the F character after the value

$filter=Distance gt 1243.224F

In MicroLite WebApi 3.0, the following operators are supported

eq – equal
gt – greater than
ge – greater than or equal
lt – less than
le – less than or equal
ne – not equal

The following string functions are also supported:

startswith – startswith(Name, 'Hayes') eq true would translate to WHERE Name LIKE ‘Hayes%’
endswith – endswith(Name, 'Hayes') eq true would translate to WHERE Name LIKE ‘%Hayes’
substringof – substringof('Hayes', Name) eq true would translate to WHERE Name LIKE ‘%Hayes%’

There are some other OData functions which are defined in OData 3.0 which MicroLite doesn’t currently support. Some of them may be added in future releases but the support in 3.0 allows for the most common types of query.

WebApi 3.0 OData Support

The biggest enhancement to the WebApi Extension in 3.0 is the support for OData queries.

A new controller has been added MicroLiteODataApiController<TEntity, TId> which is in the MicroLite.Extensions.WebApi.OData namespace. This extends the base MicroLiteApiController<TEntity, TId> so you can add OData support to “entity” controllers.

As per the MicroLiteApiController<TEntity, TId>, the OData support is opt-in so you need to create a public method called Get which accepts a parameter of ODataQueryOptions and calls the base class to return the response

public HttpResponseMessage Get(ODataQueryOptions queryOptions)
{
    return this.GetEntityResponse(queryOptions);
}

The following query options are currently supported:

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

Given the following class:

public class Customer
{
    public int CustomerId { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public DateTime Joined { get; set; }
}

and the corresponding controller:

public class CustomerController : MicroLiteODataApiController&lt;Customer, int&gt;
{
    public CustomerController()
    {
        // This MaxTop will default to 50 if not otherwise specified &amp; 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;
    }

    public HttpResponseMessage Get(ODataQueryOptions queryOptions)
    {
        return this.GetEntityResponse(queryOptions);
    }
}

The ValidationSettings property allows you to limit the query options which can be used with the controller and also limit the number of results returned per request.

Example queries:

$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: /api/customer?$select=CustomerId,Forename,Surname

would return results such as

[{ "CustomerId": 1, "Forename": "John", "Surname": "Smith" }, { "CustomerId": 2, "Forename": "Joe", "Surname": "Bloggs" } ]

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 – 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)

URI /api/customer?$filter=Joined gt datetime'2010-01-01' and Surname eq 'Smith'

would return all customers with the surname Smith who joined after 1st Jan 2010.

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

URI /api/customer?$skip=50&$top=50

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

URI /api/customer?$orderby=Surname, Joined desc

would sort by Surname ascending and then within each Surname, Joind date descending.

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

$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 /api/customer?$format=json

regardless of the content-type header value, return the results in XML:
URI /api/customer?$format=xml

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

URI /api/customer?$inlinecount=allpages

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

URI /api/customer?$inlinecount=none

do not include a count in the results – this is the default behavior if not specified.

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

WebApi 3.0 MicroLiteApiController update

MicroLiteApiController<TEntity, TId>

It now contains a new controller MicroLiteApiController<TEntity, TId>.

There are 2 generic args, one is to specify the entity type, the other the type used by the identifier property (usally int but MicroLite supports other identifier types).

The new controller supports Get, Post, Put and Delete on an opt-in basis. The methods are all declared protected, so in order to use them you need to create a public method which calls the protected one. The reasons for this are to make the functionality opt-in not opt-out which is safer and it works nicely with the WebApi help extension.

In order to use the new controller, simply create a custom controller which inherits from it and provides the type which the controller will deal with.

For example, if we have a customer class we can create a CustomerApiController:

public class CustomerApiController : MicroLiteApiController<Customer, int>
{
     ...
}

The methods all return HttpResponseMessage, the base controller is responsible for setting the HttpStatus code (e.g. 200, 404) depending on the request type and whether the request is successful.

To enable a HTTP action, simply implement the public version of the method and call the protected version.

public HttpResponseMessage Delete(int id)
{
     return this.DeleteEntityResponse(id);
}
public HttpResponseMessage Get(int id)
{
     return this.GetEntityResponse(id);
}
public HttpResponseMessage Post(Customer entity)
{
     return this.PostEntityResponse(entity);
}
public HttpResponseMessage Put(int id, Customer entity)
{
     return this.PutEntityResponse(id, entity);
}

The MicroLiteApiController&lt;TEntity, TId> class can be used to reduce the amount of boiler plate repetitive code you need to write in order to create WebApis.