Advanced OData Tutorial with Simple.OData.Client

This article describes advanced OData scenario, both for the most recent OData protocol (V4) and earlier versions. The article was inspired by the Advanced OData Tutorial article published at the odata.org. The original article describes the HTTP communication level: it shows how to build URLs, which verbs to use and what response to expect. Most of developers prefer using some kind of library to encapsulate OData HTTP communication, and we are going to study how to solve the advanced OData scenarios using Simple.OData.Client. This library supports all OData protocol versions and can be installed as a NuGet package for either OData V1-3, V4 or as version-agnostic client. All library versions are packaged as Portable Class Library with support for .NET 4.x, Windows Store, Windows Phone 8, Silverlight 5, Xamarin iOS and Xamarin Android platforms.

Creating client instance

To communicate with OData service we need an instance of ODataClient. It can be created either from its URL string or using ODataClientSettings. Here’s the simplest version:

var client = new ODataClient("http://services.odata.org/V4/TripPinServiceRW/");

And here is a slightly more complicated example where we instruct the client not to raise exceptions on 404 error and trace all requests so we can check the HTTP communication:

var client = new ODataClient(new ODataClientSettings("http://services.odata.org/V4/TripPinServiceRW/")
{
    IgnoreResourceNotFoundException = true,
    OnTrace = (x, y) => Console.WriteLine(string.Format(x, y)),
});

In the examples above we used an address of Microsoft’s TripPin sample service. This is an OData V4 service that exposes most of the essential OData features, and this is the one we will be using through this article.

Choosing API flavor

Despite the word “Simple” in its title, Simple.OData.Client actually supports three API flavors: typed, dynamic and untyped.

Typed API is what most developers expect when writing C# code. OData protocol is about exposing domain-specific resources over HTTP, and if we provide a set of corresponding C# entity classes, the client will perform necessary conversions of both OData query strings and query results. At the present time Simple.OData.Client doesn’t include entity generation tool, so you will have to write entity classes yourself. Note that classes generated by WCF Data Services proxy generator are not compatible with Simple.OData.Client because they require use of context, and Simple.OData.Client is as stateless as REST protocol itself.

Dynamic API is works without entity classes, using dynamic C# syntax. It is best for OData service exploration, when all you need to consume OData feed is just a few lines of code. Moreover, the syntax of this code will be very similar to the syntax of typed API (and in fact it is the same API, just different overloads), so you can later easily convert your dynamic code to become typed.

Finally, untyped API is what the client uses internally where all data are stored in collections of IDictionary. This syntax is also exposed and fits explorarion and ad-hoc access scenarios. In our examples we will be using typed API flavors but will show for couple of examples its dynamic counterpart. They are interchangeable.

Retrieving top-level collections

To retrieve entries from an OData service collection, we only need to know the collection name. If the collection name matches the name of our entity type (either in singular or plural form), the client will manage to figure out the name of the corresponding OData resource. Otherwise we can send the name of the collection with the method call. Here how we can retrieve the entries from People collection:

var people = await client
    .For<Person>()
    .FindEntriesAsync(annotations);

For an entry-level introduction to OData there probably wouldn’t be more to say about how to retrieve top-level OData collection elements, but this is an advanced tutorial, so we need to complicate the things. If you checked the content of the sample TripPin database, you would discover 20 items in People collection. And if you check the count of items returned by code above, you will find that it’s only 8. So where is the rest?

By inspecting the HTTP traffic we can discover some additional data returned together with People items, among them so called OData annotations. Annotations supply extra information about the data being retrieved like links to endpoints that can be accessed to perform further operations with the response data. But sometimes these links are also essential to fully perform the current operation. To prevent the service from being overloaded by unconstrained requests (e.g. requesting all data from a particular collection), the service may issue its own constraints on such requests together with a hint about how to retrieve the rest of data. Simple.OData.Client can handle such annotations, so the code to obtain all People entries will look like this:

    var annotations = new ODataFeedAnnotations();
    var people = await client
        .For<Person>()
        .FindEntriesAsync(annotations)
        .ToList();

    while (annotations.NextPageLink != null)
    {
        people.AddRange(await _client
            .For<Person>()
            .FindEntriesAsync(annotations.NextPageLink, annotations));
    }

Expanding associated collections

If you look at TripPin service metadata, you will see that People collection refer to other collections: emails, addresses, friends, trips and photos. OData protocol is lazy, it doesn’t fetch all associated data unless explicitly requested. Here how we can expand People key lookup result to include Trips and Friends:

    var person = await client
        .For<Person>()
        .Key("russellwhyte")
        .Expand(x => new { x.Trips, x.Friends })
        .FindEntryAsync();

In this example we expanded the result containing a single person data, but expansions can also be applied to requests for multiple items.

In case you have opted for a dynamic syntax, here’s the corresponding code:

    var x = ODataDynamic.Expression;
    var person = await client
        .For(x.People)
        .Key("russellwhyte")
        .Expand(x.Trips, x.Friends)
        .FindEntryAsync();

As you can see, the dynamic syntax is very similar and differs in the following:

  • You need to define somewhere in the code an instance of OData dynamic expression (ODataDynamic.Expression). You don’t need to define it every time you make a call, actually it’s sufficient to define it once for the whole application. This variable is an intermediate placeholder for expressions.
  • Once a variable of ODataDynamic.Expression is instantiated, you can use it anywhere you would use any typed expression, typically generic type specifiers and lambda expressions.

Navigating to associated collections

Results expansions enrich results with associated information, but what if we only need that associated information and are not interested in the root level data. Continuing exploration of People, we will now lookup a person, navigate to one of his trips and then fetch all plan items registered on that trip. Here’s how this can be achieved:

    var planItems = await client
        .For<Person>()
        .Key("russellwhyte")
        .NavigateTo(x => x.Trips)
        .Key(1003)
        .NavigateTo(x => x.PlanItems)
        .FindEntriesAsync();

Note that we had to call NavigateTo method twice: first to advance from the People entry to Trips collection (thus abandoning People details like if we started from Trips collection), and then advancing to PlanItems collection (again, abandoning Trips details). The result will contain a collection of PlanItems data, just like if it was a top-level collection, only that if will contain only plan items for the specific trip of the specific person.

Using Any and All clauses

Now that we know how to retrieve OData collections on different levels, let’s have a look at how we can filter them using Any and All quantors. Suppose we want to fetch people information that includes their trips but only if the trip budget was over $10000. Here’s what we do:

    var flights = await client
        .For<Person>()
        .Filter(x => x.Trips
            .All(y => y.Budget > 10000d))
        .Expand(x => x.Trips)
        .FindEntriesAsync();

To make the search criteria more complex, let’s include both Any and All clauses. We will now search for people with trips all of them would contain at least one plan item with duration longer than 4 hours:

    var duration = TimeSpan.FromHours(4);
    var flights = await client
        .For<Person>()
        .Filter(x => x.Trips
            .All(y => y.PlanItems
                .Any(z => z.Duration < duration)))
        .FindEntriesAsync();

And here’s the same operation written using dynamic C# syntax:

    var x = ODataDynamic.Expression;
    var duration = TimeSpan.FromHours(4);
    var flights = await client
        .For(x.People)
        .Filter(x.Trips
            .All(x.PlanItems
                .Any(x.Duration < duration)))
        .FindEntriesAsync();

Note that we didn’t have to use different variables in different lambda-expressions: the “x” dynamic expression variable is recycled after each use so it can be used again in the next clause.

Querying singletons

Singleton concept is a newcomer to OData. What if one particular element of the OData collection has a distinct role of being the one and only when it comes to certain quality? A company that runs a Web shop may be registered in the Company database together with its clients, but it might be convenient to expose its details in a way that makes it easy to refer to that company without hard-coding its ID in the client application. This can achieved using OData singletons.

A singleton in OData is a top-level collection that contains only one item. You can’t search for items within the singleton, it doesn’t make sense. You can only grab that only record it contains.

    var person = await client
        .For<Person>("Me")
        .FindEntryAsync();

Note that we only had to specify a different collection name (“Me”) and the command doesn’t have a query filter or key, otherwise it looks just like a request to People collection. And the singleton quality only applies to the top-level element – the “Me” person may refer to other collections that can be navigated in the same way like demonstrated earlier.

Subclassing search criteria and results

Subclassing is one of the less known features of OData, but it’s quite powerful. In addition to grouping data into different collections, it is also possible to categorize them within each collection as being data of different subtype of the collection type. Moreover, it is also possible to search for data of the specific type. Collections of subclassed data are called derived collections.

Suppose we want to retrieve the given persons’s plan items but we also want to restrict the plan items by only flights and include flight details not exposed by the PlanItem collection. Simple.OData.Client has a clause As that serves exactly this purpose:

    var flights = await client
        .For<Person>()
        .Key("russellwhyte")
        .NavigateTo(x => x.Trips)
        .Key(1003)
        .NavigateTo(x => x.PlanItems)
        .As<Flight>()
        .FindEntriesAsync();

Flight definition includes additional fields like FlightNumber and Airline that don’t exist in PlanItem definition, and these extra properties will be retrieved by the client as long as it uses As clause. And once we navigate to the subclass, we can write query expressions that include fields defined by that subclass, like in the example below where we lookup for a flight with the specific flight number among the given person’s flights:

    var flights = await client
        .For<Person>()
        .Key("russellwhyte")
        .NavigateTo(x => x.Trips)
        .Key(1003)
        .NavigateTo(x => x.PlanItems)
        .As<Flight>()
        .Filter(x => x.FlightNumber == "FM1930")
        .FindEntriesAsync();

Modifying derived collection entries

Ability to specify derived collections in search criteria is quite useful, but there must also be a way to create, updated and delete subclassed data. Deletion doesn’t require additional functionality because OData resources are always deleted by key. They are also updated by key, but updating derived collections need special attention since a client should be able to send values of the properties that are only defined in the subclass. The same goes for insertion where a client needs to send derived collection property values.

Here is the syntax of the statement that inserts into person’s PlanItems an entry of a type Event. Event type is derived from PlanItem and adds a couple of properties (Descrption and OccursAt).

    var tripEvent = client
        .For<Person>()
        .Key("russellwhyte")
        .NavigateTo<Trip>()
        .Key(1003)
        .NavigateTo(x => x.PlanItems)
        .As<Event>()
        .Set(CreateEventDetails())
        .InsertEntryAsync();

To make the code easier to read, I extracted the method CreateEventDetails that initialized properties of the Event instance:

    private Event CreateEventDetails()
    {
        return new Event
        {
            ConfirmationCode = "4372899DD",
            Description = "Client Meeting",
            Duration = TimeSpan.FromHours(3),
            EndsAt = DateTimeOffset.Parse("2014-06-01T23:11:17.5479185-07:00"),
            OccursAt = new EventLocation()
            {
                Address = "100 Church Street, 8th Floor, Manhattan, 10007",
                BuildingInfo = "Regus Business Center",
                City = new Location.LocationCity()
                {
                    CountryRegion = "United States",
                    Name = "New York City",
                    Region = "New York",
                }
            },
            PlanItemId = 33,
            StartsAt = DateTimeOffset.Parse("2014-05-25T23:11:17.5459178-07:00"),
        };
    }

Updating the event uses the same technique:

    var tripEvent = client
        .For<Person>()
        .Key("russellwhyte")
        .NavigateTo<Trip>()
        .Key(1003)
        .NavigateTo(x => x.PlanItems)
        .As<Event>()
        .Key(33)
        .Set(new { Description = "This is a new description" })
        .UpdateEntryAsync();

Note that the reason we need to navigate to PlanItems collection via Person is that plan items don’t have a top-level collection – they are contained in their respective person’s details. Otherwise we could start right from PlanItems.

Executing functions and actions

OData has supported so called service operations for a long time, but the version 4 of OData protocol has a clear distinction between functions and actions. Functions don’t have side effects and are usually executed using GET command (although the service may support sending function arguments as POST content). Actions has side effect and following REST principles are executed using POST. Both function and actions can be bounded and unbounded which means that they are applied to a collection or the whole service respectively.

Here’s how Simple.OData.Client can execute unbound function GetNearestAirport that takes geolocation as an input and returns the closest airport to the specified coordinates:

    var airport = await client
        .Unbound<Airport>()
        .Function("GetNearestAirport")
        .Set(new { lat = 100d, lon = 100d })
        .ExecuteAsSingleAsync();

And this is an example for unbound action:

    await client
        .Unbound()
        .Action("ResetDataSource")
        .ExecuteAsync();

To execute a bound function or action, we need to specify the collection. In the following example we execute an action ShareTrip that shares the person’s trip information with another person.

    await client
        .For<Person>()
        .Key("russellwhyte")
        .Action("ShareTrip")
        .Set(new { userName = "scottketchum", tripId = 1003 })
        .ExecuteAsSingleAsync();

Bounded function and actions don’t need to be applied to top-level collection. The OData service metadata specifies only the type the function or action is bound to, not an entity set.

Executing OData batch operations

Last but not least we will show how to use Simple.OData.Client with batch operations. Developers sometimes think of OData batches as transactions, but this is not correct. Batches in OData are used to optimize HTTP traffic and reduce the number of roundtrips. You can always cancel the batch while it is being built (and it will cancel all its operations) but once the batch is sent to the server, you can not ensure all-or-nothing behavior. The OData service executes batch operations one by one without ability to rollback earlier executed operations in case of a failure. But that’s not all: there is no guarantee that the outcome of the current operation will be available for the next one, neither there is a guarantee that it will not. It all depends on how the service works, so when executing a series of OData operations as a batch, don’t put any transactional semantics in it without checking the service implementation.

The following example executes a batch that consists of three operations: retrieving all airlines, creating a new airline and retrieving all airlines again. If you run this batch on the TripPin service example, you will find that although a new airline is created successfully, it will not be included in the list of airlines returned by the next batch operation call. This is not an error, just a service behavior, as mentioned above.

    IEnumerable<Airline> airlines1 = null;
    IEnumerable<Airline> airlines2 = null;

    var batch = new ODataBatch(client);
    batch += async c => airlines1 = await c
       .For<Airline>()
       .FindEntriesAsync();
    batch += c => c
       .For<Airline>()
       .Set(new Airline() { AirlineCode = "TT", Name = "Test Airline"})
       .InsertEntryAsync(false);
    batch += async c => airlines2 = await c
       .For<Airline>()
       .FindEntriesAsync();
    await batch.ExecuteAsync();

Also note that you only need to await batch operations in case you need to get hold of its result. The operation in the middle (insertion) doesn’t need to store its result, so it doesn’t need to be awaited.

Resolving FileNotFoundException when using Simple.OData.Client in iOS applications

Several users of Simple.OData.Client 4.0 pre-release reported about an error when using the library on iOS platform. An attempt to send an OData request resulted in FileNotFoundException with the error message about the V3 or V4 adapter, e.g.:

System.IO.FileNotFoundException: Could not load file or assembly 'Simple.OData.Client.V3.Adapter' or one of its dependencies.

This error occurs only on iOS platform, and it is caused by application size optimization performed by the iOS linker. The linker scans applications dependencies and strips out all unused assemblies. Or should I say – assemblies it suspects to be unused. To reduce memory footprint, Simple.OData.Client 4.0 loads only assemblies that are required by the selected version of OData protocol, and the root adapter assembly is loaded by reflection making the iOS linker believe that it’s unused.

This is in fact well-documented behavior, and there are several workarounds. Some of them requires marking code to be preserved with special attributes, but Simple.OData.Client is a packaged as a portable class library, so it can’t have dependencies on platform-specific definitions. An alternative is to include in the main application assembly a single line of code referencing the OData adapter assembly. Here’s how you do it if your application uses OData services over V3 protocol:

Simple.OData.Client.V3Adapter().Reference();

And of the code for V4 protocol is similar:

Simple.OData.Client.V3Adapter().Reference();

Note that this code does nothing. Absolutely nothing. So you can place it anywhere within the iOS application assembly. And it’s only iOS apps that need it. Android, Windows Phone and desktop applications will run fine without an explicit adapter reference.

Breaking change in Simple.OData.Client 4.0: OData batch processing

One month ago I announced a new major release of Simple.OData.Client, and in this post I would like to describe one of its few breaking changes: executing OData batch operations.

Earlier versions of Simple.OData.Client had a simple but somewhat naive (and incomplete) support for OData batches. Here’s an example:

using (var batch = new ODataBatch(serviceUri))
{
    var client = new ODataClient(batch);
    await client
        .For&lt;Product&gt;()
        .Set(new { ProductName = "Test3", UnitPrice = 21m })
        .InsertEntryAsync(false);
    await client
        .For&lt;Product&gt;()
        .Set(new { ProductName = "Test4", UnitPrice = 22m })
        .InsertEntryAsync(false);
    batch.Complete();
}

This example works fine because it consists only of insert operations and don’t return anything back. While data modification requests represent a primary use of batch operations, OData batch protocol supports data retrieval (GET) operations that can be mixed with POST/PUT/PATCH/DELETE requests in a single batch. And GET requests didn’t work with earlier Simple.OData.Client versions because its batch API was modeled after SQL transaction API that executes individual statements as they come with possibility to rollback them back. OData batch is a different beast: it accumulates multiple operations and sends them at once as a single HTTP POST request once all operations are written into a batch message. Such behavior prevents responses from individual batch operations to be assigned to local variables before the batch is executed. So the code above succeeds in following “tell don’t ask” principle but it will fail if there is a need to ask about something within a batch.

Batch API in Simple.OData.Client 4 is completely rewritten to properly reflect OData batch behavior. It uses a concept of promises which is implemented using C# lambda expressions. The batch operations are recorded as a sequence of Func delegates having signature Func<IODataClient, Task>. So the statement above will look like this:

var batch = new ODataBatch(serviceUri);
batch += c =&gt; c
    .For&lt;Product&gt;()
    .Set(new { ProductName = "Test3", UnitPrice = 21m })
    .InsertEntryAsync(false);
batch += c =&gt; c
    .For&lt;Product&gt;()
    .Set(new { ProductName = "Test4", UnitPrice = 22m })
    .InsertEntryAsync(false);
await batch.ExecuteAsync();

Note that you don’t need to await batch operations as long as they don’t return any results: the operations are not executed instantly, they are recorded in a single batch message that is sent to the server in ExecuteAsync call.

But what if we need to return some data as a part of a batch? Here’s how it can be achieved:

IEnumerable&lt;Airline&gt; airlines1 = null;
IEnumerable&lt;Airline&gt; airlines2 = null;

var batch = new ODataBatch(client);
batch += async c =&gt; airlines1 = await c
    .For&lt;Airline&gt;()
    .FindEntriesAsync();
batch += c =&gt; c
    .For&lt;Airline&gt;()
    .Set(new Airline() { AirlineCode = "TT", Name = "Test Airline"})
    .InsertEntryAsync(false);
batch += async c =&gt; airlines2 = await c
    .For&lt;Airline&gt;()
    .FindEntriesAsync();
await batch.ExecuteAsync();

This code demonstrates how to implement scenario described in Advanced OData Tutorial at odata.org where the first batch operation retrieves a list of airlines, the second creates a new airline record and the third one refreshes the airline list (remember that it’s up to the server to return the updated or original data collection – OData batches are not database transactions, they don’t conform to ACID principles). Note also the use of async/await pattern in both FindEntriesAsync calls. I wrote earlier that you don’t need to await for operations being recorded but if you want to get hold of their responses you will either have to assign them to variables of type Task<T> or use async/await.

OData batch protocol also defines a way to reference newly created resources so they can be used to create associations with other resources. This scenario is also supported by Simple.OData.Client:

var product1 = new Product() {ProductName = "Test1", UnitPrice = 21m};
var product2 = new Product() {ProductName = "Test2", UnitPrice = 22m};

var batch = new ODataBatch(serviceUri);
batch += c =&gt; c
    .For&lt;Product&gt;()
    .Set(product1)
    .InsertEntryAsync(false);
batch += c =&gt; c
    .For&lt;Product&gt;()
    .Set(product2)
    .InsertEntryAsync(false);
batch += async c =&gt; await c
    .For&lt;Category&gt;()
    .Set(new { CategoryName = "Test3", Products = new[] { product1, product2 } })
    .InsertEntryAsync(false);
await batch.ExecuteAsync();

Here you see how Product entries “product1” and “product2” created in the batch are then referenced in the same batch from another new entry of a type Category that creates a link to a collection of associated products identified by the navigation property “Products”.

The revised batch API is available in Simple.OData.Client 4.0 RC6.

Announcing Simple.OData.Client 4.0: support for OData V4 and JSON payload

A few months ago I published a roadmap for Simple.OData.Client development which I was trying to follow. Today I am happy to announce a major revision (in fact major rewrite) of the library that now supports OData protocols from 1 to 4 and both Atom and JSON payload.

To achieve that I based the library parsers and formatters on Microsoft’s ODataLib that exists in two incarnations: for OData versions 1 to 3 (Microsoft.Data.OData) and for OData version 4 (Microsoft.OData.Core). Both ODataLib libraries implement similar sets of classes and interfaces (even with the same names), but they have different type identities which makes them incompatible. To make them transparent to the clients, Simple.OData.Client uses adapters libraries that communicate with respective ODataLib assemblies. These pictures show the libraries dependencies.

In case you use OData from desktop apps, the easiest is just to continue using Simple.OData.Client NuGet package that has everything to consume OData feeds of any OData version. However, mobile applications are usually more cautious about program footprint, and since in most cases an application connects to a specific version of OData service using specific version of OData protocol, there is no need to drag a couple of megabytes of unused dependencies, and in that case I recommend to install a NuGet package of Simple.OData.Client just for the given OData protocol version. Here are the packages:

  • Simple.OData.Client – supports all OData protocol versions, installs both sets of ODataLib components;
  • Simple.OData.V3.Client – supports versions of 1 to 3 of OData protocol, installs Microsoft.Data.OData package and dependencies;
  • Simple.OData.V4.Client – supports version 4 of OData protocol, installs Microsoft.OData.Core package and dependencies;

All packages support both Atom and JSON payload, but Atom payload is currently disabled in ODataLib V4 (should come later), so for the time being V4 clients can only use JSON.

Also note that Simple.OData.Client requires Microsoft.OData.Core 6.7.0 NuGet package and not the latest released 6.8.0. This is due to problems reading schemas with Enum types in the package 6.8.0 which I hope will be fixed soon.

Try it out, and if you find any issues please report them here.

Second look at Xamarin.Forms: building OData client

A few weeks ago I wrote a blog post about getting started with Xamarin.Forms. While I went through the full cycle of creating Xamarin.Forms applications on all three supported mobile platforms, the actual application (“Hello, Forms” greeting) was too dull to give an impression about the product UI capabilities.

After that I continued working on my pet project – a cross-platform OData client library Simple.OData.Client. In addition to a NuGet PCL package I also wanted to publish the library in Xamarin Component Store, and Xamarin Store submissions require samples for all supported platforms. Earlier I planned to write three separate samples, but with the release of Xamarin.Forms there is a much easier way to write small prototype-alike apps for such purposes. I asked folks at Xamarin whether it would be acceptable to submit component samples written using Xamarin.Forms, and it turned out that it would be the first such submission but it would be OK and in fact worth gathering some experience.

Prototyping NuGetFinder

The sample that I planned to write had to demonstrate capabilities of an OData library, and NuGet is definitely the most popular OData feed among developers. I decided to write a simple NuGet package finder with three pages: a page to specify package search criteria, a result page with a list of matching packages and a page with package details. I quickly made a UI prototype using Balsamiq Mockups.

Mockups

Choosing between Portable and Shared projects

As I wrote in my “First look” post, Xamarin Visual Studio add-on and Xamarin Studio install mobile apps templates that give developers a choice between applications based on Shared (Universal) projects and Portable projects. The first option is about sharing only projects assets, not resulting binaries. The second option is based on portable class libraries (PCL).

I am a big fan of portable class libraries, and Simple.OData.Client itself is a PCL, but after some considerations I decided to build Xamarin Store samples based on Shared projects. The main reason for this is that even though I wanted samples to reuse common code, I also wanted them to be autonomous, so a sample project assembly would contain its user interface rather that referencing another PCL.

C# or XAML?

Xamarin.Forms support describing user interface either using markup language (its own XAML dialect) or directly in C#. Both methods give same results, but for the time being none of them has comprehensive documentation, and with C# you are guarded by a compiler and guided by Intellisense. Writing XAML you must know markup and watch typos. I concluded that at this point it will be easier to describe UI elements in C#, but I plan to use XAML in the future when it’s better documented.

Where are those radio buttons?

I created a solution with shared UI assets and applications for iOS, Android and Windows Phone and started implementing its UI based on my mockups. I am a backend developer during daytime, so I have good excuses for not knowing much about available UI mobile controls. And it took me some time to realize that there is not such a thing as cross-platform radio button control. Xamarin doesn’t want to repeat a mistake made by designers of Java applets and offer cross-platform user interface elements that would look equally bad on each platform. Instead they offer UI abstractions that can translate into native controls. And since Xamarin.Forms is a multiplatform product, its UI elements are limited with those that can be found on all three platforms. Thus no radio or check buttons. I ended up with Picker control that provides the same functionality (although with a very different look).

Search page

Search page is the page that sets up and performs communication with the NuGet OData feed. The user enters search details and clicks “Search” button triggering the following code:

searchButton.Clicked += async (sender, e) =&gt;
{
    var packages = await FindPackagesAsync();
    var resultsPage = new ResultsPage(packages);
    await this.Navigation.PushAsync(resultsPage);
};

And here’s the definition of FindPackagesAsync:

private async Task&lt;IEnumerable&lt;Package&gt;&gt; FindPackagesAsync()
{
    int count = 0;
    switch (_resultSizePicker.SelectedIndex)
    {
        case 0: count = 10; break;
        case 1: count = 25; break;
        case 2: count = 100; break;
    }

    var odataClient = new ODataClient("https://nuget.org/api/v1");
    var command = odataClient
        .For&lt;Package&gt;("Packages")
        .OrderByDescending(x =&gt; x.DownloadCount)
        .Top(count);

    switch (_sortPicker.SelectedIndex)
    {
        case 0:
            command.OrderByDescending(x =&gt; x.DownloadCount);
            break;
        case 1:
            command.OrderBy(x =&gt; x.Id);
            break;
        case 2:
            command.OrderByDescending(x =&gt; x.LastUpdated);
            break;
    }

    if (!string.IsNullOrEmpty(_searchText.Text))
    {
        command.Filter(x =&gt; x.Title.Contains(_searchText.Text) &amp;&amp; x.IsLatestVersion);
    }
    else
    {
        command.Filter(x =&gt; x.IsLatestVersion);
    }

    command.Select(x =&gt; new {
        x.Id, x.Title, x.Version, x.LastUpdated, x.DownloadCount, 
        x.VersionDownloadCount, x.PackageSize, x.Authors, x.Dependencies });

    return await command.FindEntriesAsync();
}

Here how the Search page looks on iPhone simulator:

SearchPage

Nothing fancy, but enough to prototype page UI on all major mobile platforms.

Results page

Results page is essentially a list of packages satisfying search criteria with an event handler for a selected item:

resultList.ItemSelected += (sender, e) =&gt;
{
    var package = (PackageViewModel)e.SelectedItem;
    var detailsPage = new DetailsPage();
    detailsPage.BindingContext = package;
    Navigation.PushAsync(detailsPage);
};

Here’s how the results pages look on an Android simulator:

ResultsPage

Details page

Selected package details are shown on a new page that consists of label and text box controls. The programming logic is very simple, here’s a code extract that assigns package title and package id:

var titleLabel = new Label() { Font = Font.SystemFontOfSize(NamedSize.Large) };
titleLabel.SetBinding(Label.TextProperty, "Title");
stackLayout.Children.Add(titleLabel);
var idLayout = new StackLayout() { Orientation = StackOrientation.Horizontal };
idLayout.Children.Add(new Label() { Text = "Package Id: " });
var idLabel = new Label();
idLabel.SetBinding(Label.TextProperty, "Id");
idLayout.Children.Add(idLabel);
stackLayout.Children.Add(idLayout);

Here’s how Details page look on Windows Phone emulator:

DetailsPage

And now there is a new Xamarin component!

These samples have been packaged and submitted together with Simple.OData.Client library. They are now available in Xamarin Component Store. And the sample source code is also available from the GitHub repository.

Component

First look at Xamarin.Forms

Today (May 29) was the Norwegian national holiday, so it was a good timing for me that Xamarin just announced availability of Xamarin 3 with the main new addition called Xamarin.Forms. So I downloaded both Windows and Mac versions and spent some time checking out how they work. This post is about setting up Xamain.Forms projects, it doesn’t contain a thorough look at its functional capabilities.

Since I have a Mac machine, I decided to try both Windows and Mac versions. To use Xamarin.Forms with Visual Studio I had to install Visual Studio 2013 Update 2 (RTM) – this is a prerequisite, earlier versions won’t work. Xamarin Visual Studio add-on installs 3 new templates in the “Mobile Apps” folder, so you have choice between applications based on Shared (Universal) projects, Portable projects or just building a portable class library (PCL).

VsProjectTypes

I selected Xamarin.Forms portable and Visual Studio created a common portable class library project (with shared form definition) and applications for all three supported platforms (Android, iOS and Windows Phone 8).

PortableAppProjects

The common PCL uses profile that supports five different platorms – in addition to mobile platforms it can also be used in desktop and Silverlight applications.

VsPortableApp1

Then I switched to MacOS, started Xamarin Studio and chose an alternative template for Xamarin.Forms solution – this time it was Shared project template.

XsProjectTypes

Xamarin Studio created a shared forms project and applications for two platforms supported for development on MacOS (Android and iOS).

SharedAppProjects

Now I could start building mobile applications. I switched back to Visual Studio and started with Windows Phone app. For the first time Windows Phone is a target of Xamarin tools platform (Xamarin Studio still supports only iOS and Android). The actual UI content (placed in a PCL and shared by all platforms) consisted of an obligatory first-app-greeting:

VsPortableApp2

I built a Windows Phone app and deployed it to a phone simulator. Note “PortableApp1.WinPhone” that appears in the application list. Executing it results in a “Hello, Forms!” message.

VsWinPhone1VsWinPhone2

Next was Android simulator. It took me some time to figure out how to select Android API version required by the app. The trick was to locate a small toolbar button that opens Android options. I chose “MonoForAndroid_API_15”.

VsAndroid1

Having selected correct version of Android Simulator, I was able to deploy PortableApp1.

VsAndroid2

 

VsAndroid3

The last platform was iOS, it required establishing a connection with Mac host. I also had to choose the Simulator device type.

VsIOS1

After the iOS deployment configuration was correctly set, Visual Studio deployed the iOS app to the iPhone simulator running on Mac.

VsIOS2

Having completed all three applications from within Visual Studio, I switched back to Xamarin Studio on Mac. There is no Windows Phone support in Xamarin Studio, so I built Android and iOS apps. The content of App.cs file in a Shared project is almost identical to its Portable project counterpart. And the Android simulator on Mac OS looks similar.

XsAndroid1

Next was iOS app and choice of its simulator.

XsIOS1

After the deployment of iOS app I had both PortableApp1 and SharedApp1 installed on the iPhone simulator – the first one was earlier installed by Visual Studio.

XsIOS2

After completion of apps with Xamarin Studio I tried swapping solutions between development environments. Here not everything went smooth. Xamarin Studio opened and built the solution created with Visual Studio (of course with exception of Windows Phone project that was ignored), but Visual Studio refused to load shared app project with a cryptic error message:

VsOpenXs

The log file contained a stack trace of the AggregatedException with not much more useful details. I described an error in Xamarin forum, and one of the suggestion was to install a Shared Project Reference Manager extension. I followed the advice, and while I no longer received the error above, Visual Studio still refused to deal with the shared project, this time hanging on project load.

VsOpenXsCrash

I also tried to create a solution based on Shared project template in Xamarin Studio for Windows, but the result was still the same: Visual Studio couldn’t handle the solutions created by Xamarin Studio. It looks like the problem is only with Shared project template – when I created with Xamarin Studio a project from Portable project template, Visual Studio had no problems with it.

So for the time being if you want to be able to swap solutions between different environments, you need to create Shared apps with Xamarin add-in to Visual Studio which can be a problem because this option requires the expensive Xamarin Business license. Hopefully this issue will be addressed soon.

I also tried to get a feeling of what it takes to author UI content in Xamarin.Forms, so I used code from a login page example.

XsSharedApp1

I only needed to edit this code once – in a Portable or Shared app, and all apps reflected the change.

VsWinPhone3XsIOS3

XsAndroid2

This a very trivial example, and I am looking forward to check more advanced scenarios. During beta testing period Xamarin.Forms had a codename QuickUI, and it’s a really way to simultaneously develop applications on all three major mobile platforms. There is no restriction in mixing native UI elements with content created with Xamarin.Forms, so the resulting apps don’t need to suffer from least common denominator design syndrome.

 

 

Simple.OData.Client roadmap: versions 2, 3 and 4

It’s been a few month since I wrote a blog post comparing features of Simple.OData.Client and WCF Data Services client. Judging from NuGet download statistics, questions and GitHub issues I can see that the library has been used in various scenarios and on various platforms, including Xamarin iOS and Android. This is indeed very encouraging but at the same time raises the bar for the platform tests, conformance to OData protocol and API expressiveness. Some of the forthcoming changes to Simple.OData.Client API are breaking, and with respect to semantic versioning I have to release them with a different major version number. So I’d like to give in this blog post a quick overview of each version.

Version 1

Initial release of Simple.OData.Client came as a library extracted from Simple.Data OData adapter to improve its granularity and portability. The library implemented HTTP communication based on HttpWebRequest and favored synchronous calls. This didn’t work well with platforms like Silverlight and Windows Phone that required asynchronous communication all the way.

Version 2

This is the most recent (in May 2014) version of Simple.OData.Client with two major changes comparing to version 1:

  • The library is now using Microsoft HttpClient PCL (Microsoft.Net.Http);
  • The library API has been redesigned to be asynchronous but it still exposes obsolete synchronous methods in addition to asynchronous ones;

I have to admit now that keeping synchronous methods was a mistake – I did it for backward compatibility, but it misleads developers in belief that they can use synchronous API on platforms where it can easily cause deadlocks. In fact, I wouldn’t recommend to use sync API on any platform except .NET 4.x. For the sake of existing .NET 4 clients I will keep adding minor changes to version 2 even after release of newer major versions of the library.

Version 3

This is already available as release candidate and contains the following significant changes:

PCL profile numbers may not say much, but this is in fact the major change although not reflected in API method signatures. PCL profile 147 corresponds to so called legacy surface area intended to fit most platforms. This requires use of internal wrappers and adapters and as it turned out results in problems – ironically on the legacy platforms. For example, I never managed to succeed using HttpClient PCL from another PCL called from a Silverlight application. So I changed the PCL targeting strategy and now Simple.OData.Client targets .NET 4.0 and Silverlight platforms via native platform-specific libraries with the its PCL targeting other platforms.

Version 4

Currently Simple.OData.Client uses its own parser and formatter that only support XML payload in the format of RSS feeds. That was the original OData message format, but the protocol has been extended with support for JSON, and being more compact, more readable and more network bandwidth friendly, JSON is becoming a preferred OData payload representation and is selected as a default format by OData feeds built using HTTP Web API. Now that Microsoft has converted its ODataLib (Microsoft.Data.OData) to support all target Simple.OData.Client platforms, I plan to retire internal Simple.OData.Client OData parser and formatter and instead use the one from ODataLib so I can ensure the same message serialization and keep the library up-to-date with most recent OData protocol updates reflected in ODataLib.

Summary: which version to use?

 

  • If you’re using Simple.Data OData adapter, you don’t need to care: just use the most recent version available at NuGet or keep using the one you’re using now if it works fine. Simple.Data OData adapter will be maintained and its dependencies will be updated so you don’t have to take any actions in regards to Simple.OData.Client.
  • If you’re using Simple.OData.Client synchronous API with .NET 4.0 applications and everything works fine, you can continue using it. For mobile applications use only asynchronous API calls.
  • The release of the version 3 is around the corner, pre-release is already available. Works much better with Silverlight clients, support for cancellation tokens, modern PCL profile widely used on Xamarin platforms.
  • Version 4 will add support for JSON payload and will be based on ODataLib. But I haven’t even started working on it.