Next week we will release an official RC of the Microsoft ASP.NET WebAPI OData assembly. This marks the third release on our way to RTM. Although this post talks about code that hasn’t been officially release yet, since all development is happening in public, if you can’t wait till next week, you can always go and get one of the nightly builds or for a more bare metal experience build it yourself from our code repository.
In this post I will cover what is new since the Alpha, if you need a more complete view of what we is currently supported I recommend you read about the August Release and the Alpha release as well.
In the alpha release to get everything (OData Actions, OData casts, OData navigations etc) working together I updated the sample to do custom routing. This routing was based on a component that understood OData Paths and dispatched to actions based on custom routing conventions. At the time we knew this was a merely a stop gap.
That code has now been refactored, improved and moved into the core code base.
The code consists of:
For a complete example of how to use all this new goodness check out the sample OData service which you can find at http://aspnet.codeplex.com in the source tree under: /Samples/Net4/CS/WebApi/ODataService.
One of the most exciting new features is the ability to specify validation rules to be applied to a query. Essentially this allows you to constrain what query options you allow against your [Queryable]. Under the hood this is all implemented via the virtual ODataQueryOptions.Validate(ODataValidationSettings) method, which you can use if you need to.
That said the 90-99% scenario is simply to specify additional parameters to the [Queryable] attribute that the control what is allowed in a query, and then before the query is processed, Web API converts those settings into an ODataValidationSettings object and calls ODataQueryOptions.Validate(..). If anything not supported is found in the AST a validation error results, and your backend Queryable never gets called.
Here are some examples:
[Queryable(AllowedQueryParameters = ODataQueryParameters.Skip| ODataQueryParameters.Top)]
This means only Skip and Top are allowed, i.e. a $filter or $orderby would result in a validation error. By default every thing is allowed, until you mention a particular setting, then only the things you list are supported.
Another example is:
[Queryable(AllowedLogicalOperators=ODataLogicalOperators.Equal)]
This says the $filter only supports the Equal operator, so for example this:
~/Customer?$filter=Name eq ‘Bob’
will pass validation but this:
~/Customers?$filter=Name ne ‘Bob’
will fail.
Checkout the new [Queryable] attribute to find out more.
This now supports patching classes that derive from the T too. This is useful if you want both these requests:
PATCH ~/Customers(1)
PATCH ~/Customers(1)/Namespace.VIP
to be dispatched to the same method, for example:
public virtual HttpResponseMessage Patch([FromODataUri] TKey key, Delta<Customer> patch) { … } Now because Delta<Customer> can also hold changes made to a VIP (i.e. a class the derives from Customer) you can route to the same method, and deal with a whole inheritance hierarchy in one action.
Another thing to notice is the new [FromODataUri] attribute, this tells Web API the key parameter is in the URL encoded as an OData Uri Literal.
We now handle DateTime or DateTimeOffset literals or properties for the first time, and we allow you to specify casts in your filter too, for example:
~/Customers?$filter=Name eq ‘Bob’ or Namespace.VIP/RelationshipManager/Name eq ‘Bob’
At this point the only thing that we don’t support (and won’t support for RTM either) is spatial types and custom OData functions inside the filter. These will come later when support for them is added to ODataLib’s ODataUriParser.
This release also includes a little support for the new OData v3 json format, and of course by RTM time we will have full support. This OData V3 json format is more efficient than our older V1/V2 json format (which incidentally the OData team has started calling ‘JSON verbose’, to make sure you know we don’t like it any more :)
The new JSON format has sub types, which allow clients to specify how much metadata they want, ranging from FullMetadata, through MinimalMetadata to NoMetadata. The RC supports the new OData JSON format only for write scenarios (i.e. responding to requests), it doesn’t currently handle read scenarios at all (i.e. request payloads that are in the new JSON format). It supports the most common payload kinds, feeds, entries, errors and service documents, and by RTM we will flesh this out to include other payloads like properties, links etc.
In the RC we don’t support NoMetadata at all, and we treat MinimalMetadata as if it is FullMetadata. We do this because MinimalMetadata means only send metadata and links that the client can’t deduce them by convention, and in the RC we don’t have anyway to tell the formatter that you are indeed following conventions. This forces us to always emit links. By RTM we will add a way to say you are following convention, and that will allow us to support MinimalMetadata properly.
Read What is JSON Light and Enabling JSON Light from WCF DS to learn more about the new OData JSON format.
As you can see we’ve been really busy making Web API a first class stack for creating and exposing OData services, ranging from supporting just the OData query syntax, through supporting the majority of the OData protocol, all the way up to supporting extra things not in OData but enabled by Web API, like for example new formats.
As always please let us know what you think.
-Alex