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.

WebApi Extension 3.0.0 Released

MicroLite.Extensions.WebApi 3.0.0 has been released on NuGet.

Configuration and Filters

In WebApi Extension 2.1 we added the ability for the extension to register the MicroLiteSession attribute globally to save you having to apply it to each controller or action which you wanted an ISession/IReadOnlySession opening for. This was done by passing a boolean value for registerGlobalFilter to the WithWebApi configuration extension.

The MicroLiteSession attribute has been moved into the Filters namespace and 2 more filters have been added, one to verify Api method parameters are not null and another to validate them if they are decorated with DataAnnotation attributes.

The configuration of the extension has also been updated, it is now required to specify a WebApiConfigurationSettings class. The WebApiConfigurationSettings class currently exposes 3 properties:

RegisterGlobalMicroLiteSessionAttribute - defaults to true
RegisterGlobalValidateModelNotNullAttribute - defaults to true
RegisterGlobalValidateModelStateAttribute - defaults to true

If you are happy to use the defaults, you can simply tell MicroLite to use the default settings:

Configure.Extensions().WithWebApi(WebApiConfigurationSettings.Default);

otherwise, simply specify the values you wish to use:

Configure.Extensions().WithWebApi(new WebApiConfigurationSettings
    {
        RegisterGlobalMicroLiteSessionAttribute = false
    });

Registering these filters at a global level means that they are called for every action on every controller and you don’t have to have the following at the start of every method on every controller.

public void Post(Customer customer)
{
     if (customer == null)
     {
          throw new ArgumentNullException("customer");
     }

     if (!this.ModelState.IsValid)
     {
          return this.Request.CreateResponse(HttpStatusCode.BadRequest, this.ModelState);
     }
}

Remember that even though the MicroLiteSession attribute is registered globally, you can still override its default behaviour on a per controller or per action basis by applying the attribute to a class/method. This is probably something you don’t need to do very often and can be left to the infrastructure to open and assign a session for your controller and begin/commit a transaction around each action.

WebApi Extension 2.1.0 Released

In the MVC and WebApi extensions post, we discussed using the GlobalConfiguration.Configuration.Filters to register the MicroLiteSessionAttribute. In MicroLite.Extensions.WebApi 2.1.0, we do that automatically when calling .WithWebApi();.

If you don’t want that to happen, simply call the overload instead to opt out of the registration .WithWebApi(registerGlobalFilter: false);

New Infrastructure Interfaces

As part of MicroLite 3.0, two new interfaces were added to the MicroLite.Infrastructure namespace:

IHaveSession and IHaveReadOnlySession

These interfaces are implemented by the controllers in the ASP.NET MVC and ASP.NET WebApi extensions and the MicroLiteSessionAttribute for each extension checks against the interfaces rather than the base controllers.

This means that if you want to, you can use the extensions without having to inherit from the base controllers.

// Instead of having to do this:
public HomeController : MicroLiteController
{
...
}

// You can do this:
public HomeController : SomeOtherController, IHaveSession
{
...
}

This allows you to use the extensions in a scenario where you cannot control the base controller you are using or if you just don’t want to have to inherit from the base MicroLite controller for any reason.