Windows Azure
Mobiles Services (WAMS) targets Windows 8 Applications in its first preview - a
great starting point on the way to supporting multiple mobile platforms down
the road. This post covers a few basics of using WAMS in managed code (C# or
VB.NET) using C# examples. You could use VB.NET just as well. Some of this is
already covered in tutorials
but you might find this useful as a cheat sheet.
A Mobile Service
created using WAMS has an http REST endpoint that can be used directly if you
like. But we also ship an SDK (currently in MSI form) that
elevates the experience quite a bit and bring it closer to the host language
and platform. This post is about the SDK experience. If you haven't already
completed the quick start and related tutorials, I strongly recommend you do
those first. This post is intended to be complementary though I do repeat a few
things to make the post a bit more self-contained.
Client
The main class is
the MobileServicesClient - the go to class for all your needs. It takes two
parameters:
- URL for the Mobile Service. This is globally unique (hence you need to pick a unique service name when you create one)
- App key: this identifies the app (since this is distributed with the app and viewable in fiddler or other browser dev tools, you could call it an "open secret"; i.e. it has identification value and no real security value)
public static MobileServiceClient
client = new MobileServiceClient(appURL,
appKey);
You start by getting
a table proxy so that
subsequent code can be strongly typed.
IMobileServiceTable<TodoItem>
TodoTable = App.client.GetTable<TodoItem>();
Don't worry, just as
in other LINQ incarnations, this table is just a proxy that knows how to
perform CRUD type operations. The following statement does NOT retrieve the
entire table down to the client. (In fact, for the app's good, we don't allow
that even otherwise but more about it later).
The client also
supports login in addition to CRUD (Create, Read, Update and Delete)
operations.
Queries
In managed code, the
query support is quite straightforward. It is basically the LINQ experience
with support for a subset that roughly covers filtering, sorting and paging
against a single collection (i.e. no joins, no groupby etc.).
Getting Results
There are a few
options to get the results of a query that is executed asynchronously (hint:
you can't just use regular ToList here; you need an awaitable task or something
that can handle async ops)
// If you just want and IEnumerable. Returns an
awaitable Task
var items0 = todoTable.ToEnumerableAsync();
// Friendly collection to iterate through
var items1 = todoTable.ToListAsync();
// More fancy data binding.
// ICollectionView, INotifyCollectionChanged,
INotifyPropertyChanged and a bunch of other interfaces are implemented
MobileServiceCollectionView<TodoItem>
items2 = todoTable.ToCollectionView();
For quick and dirty
prototyping, I prefer to use MobileServiceCollectionView (MSCV). For more
specific use; it is better to have your own custom implementation of ICV etc.
Filtering
MobileServiceTableQuery<TodoItem>
query = todoTable.Where(todoItem => todoItem.Complete == false);
You could use the
comprehension syntax if you prefer. It is just LINQ, though within limits of
supported operators and member functions.
Lookup helps you get
a single object.
// Singleton or null
var item0 = await todoTable.LookupAsync(id);
if (item0 != null)
{
// For illustrative purposes only
MessageDialog md = new MessageDialog(item0.Text);
var ignoreAsyncResult = md.ShowAsync();
}
Sorting
As in case of
filtering, you can use the standard LINQ operators with lambda or comprehension
syntax:
var query = todoTable.OrderBy(t => t.Text);
In addition, you can
also use other operators like ThenBy, OrderByDescending etc.
Paging
For mobile apps,
data is often bound to a UI so it is often best retrieved a page at a time. On
slower networks, even data retrieved for other purposes (i.e. not for directly
displaying in a UI) should be limited through paging. Paging relies on LINQ Skip
and Take operators.
// First page
var query = todoTable.OrderBy(t => t.Text).Take(page_size);
// For (n+1)th page
var query = todoTable.OrderBy(t =>
t.Text).Skip(n*page_size).Take(page_size);
Mobile Services
runtime (server-side) provides paging by default by restricting the results to
50 objects. This is usually appropriate for most UI binding scenarios. You can
override that by applying Take(n) where n can be any number from 1 to 1000.
There is also a way
to get the total count of all objects matching your query (not just the first
page). I will cover that in a separate post later.
CUD
Create, Update and
Delete operations are quite straightforward.
// Insert a new record
TodoItem newItem = new TodoItem {
Text = "Complete C#
Client blog post",
Complete = false };
await todoTable.InsertAsync(newItem);
// Update a record
newItem.Complete = true;
await todoTable.UpdateAsync(newItem);
// Delete a record
await todoTable.DeleteAsync(newItem);
Insert operation
performs dynamic schematization. You don't need to go through the ceremony of
creating a table with typed columns etc. Mobile Services run-time looks at the
properties in the JSON payload and adds eponymous column(s) if they are not
already present. It looks at the value of the property to infer the type. Of
course, because the base types in JavaScript (which is what is used for server
scripts and underlies JSON) are fairly simple, the list of types is much
smaller than that in .NET or SQL. Here is a quick table that describes the
types currently used.
JSON Value
|
T-SQL Type
|
Numeric values
(integer, decimal, floating point)
|
Float(53)
|
Boolean
|
Bit
|
DateTime
|
DateTimeOffset(3)
|
String
|
Nvarchar(max)
|
Likewise, update
operation can also perform dynamic schematization if necessary.
Typically you want
dynamic schematization when you are developing your app for rapid turnaround
and changes. When you deploy, it is usually a good idea to "lock
down" the schema by turning off dynamic schematization so users of your
app can't accidentally or maliciously expand the schema. Mobile Service
developers can turn off dynamic schematization in the portal
("CONFIGURE" tab).
For the delete
operation, the only property on newItem object that matters is the ID assigned
by Mobile Service when the object was created in the table.
Untyped Usage
The C# client is
primarily designed for strongly typed scenarios. However, sometimes a more
loosely typed experience is convenient (e.g. objects with open schema). That is
enabled as follows. In queries, you lose LINQ and you have to dropped down to
effectively the wire-format.
// Get an untyped table reference
IMobileServiceTable untypedTodoTable = App.MobileService.GetTable("TodoItems");
// Lookup untyped data using odata
IJsonValue untypedItems = await
untypedTodoTable.ReadAsync("$filter=complete
eq 0&$orderby=text");
You get back JSON
value that you can use like a property bag.
Login
I strongly recommend
going through the tutorial on our dev center to
understand authentication
and users. This is just for completing the cheat sheet:
// Log in
MobileServiceUser user = await App.MobileService.LoginAsync(windowsLiveToken);