September 2015

Volume 30 Number 9

Cloud-Connected Mobile Apps - Build a Xamarin App with Authentication and Offline Support

By Kraig Brockschmidt

As described in the first part of this two-part series, “Create a Web Service with Azure Web Apps and WebJobs” (msdn.microsoft.com/magazine/mt185572), in the August issue, many mobile apps today are connected to one or more Web services that provide valuable and interesting data. Although it’s easy to just make direct REST API calls to those services and process responses in the client, such an approach can be costly in terms of battery power, bandwidth and throttling limitations imposed by different services. Performance might also suffer on lower-end hardware. It makes sense, then, to offload work to a custom back end, as we demonstrate with the “Altostratus” project we’ll discuss in this article.

The Altostratus back end, discussed in Part 1, periodically gathers and normalizes “conversations” from StackOverflow and Twitter (just to use two different data sources) and stores them in a Microsoft Azure database. This means that the exact data needed by clients can be served up by the back end directly, allowing us to scale the back end in Azure to accommodate any number of clients without hitting the throttling limits of the original providers. By normalizing the data on the back end to match what the client needs, we also optimize data exchange through the Web API, conserving the ever-scarce resources of mobile devices.

In this article, we’ll discuss the details of the client app (see Figure 1). We’ll begin with the app’s architecture to set the overall context, then go into our use of Xamarin and Xamarin.Forms, authentication with the back end, building the offline cache, and building with Xamarin on Team Foundation Server (TFS) and Visual Studio Online.

The Xamarin Mobile App Running on an Android Tablet (Left), a Windows Phone (Middle) and an iPhone (Right)
Figure 1 The Xamarin Mobile App Running on an Android Tablet (Left), a Windows Phone (Middle) and an iPhone (Right)

Client App Architecture

The client app has three main pages or views: Configuration, Home and Item, whose classes share these names (see Figure 2). A secondary Login page has no UI and is simply the host for the OAuth provider Web pages. Using a basic Model-View-ViewModel (MVVM) structure, each main page except for Login has an associated view model class to handle the binding relationships between the views and the data model classes that represent items, categories and configuration settings (including a list of authentication providers).

The Architecture of the Altostratus Client App, Showing the Names of the Primary Classes Involved (Files in the Project Match These Class Names Unless Indicated)
Figure 2 The Architecture of the Altostratus Client App, Showing the Names of the Primary Classes Involved (Files in the Project Match These Class Names Unless Indicated)

 (Note: Developers often prefer to separate the XAML views into a portable class library [PCL] that’s separate from the view models and other classes, allowing designers to work independently with the views in tools like Blend. We didn’t make that separation to keep the project structure simple, and also because Blend doesn’t work with the controls in Xamarin.Forms at this time.)

The data model always populates these objects from a local SQLite database, which is pre-populated on first run of the app. Synchronization with the back end, which happens in the data model, is a straightforward process of retrieving new data (as little as possible to minimize network traffic), updating the database with that data, cleaning out any old data, and instructing the data model to refresh its objects. This triggers an update of the UI, thanks to data binding with the view models.

As we discuss later, a number of different events trigger a sync: a refresh button in the UI, changing the configuration, authenticating with the back end (which retrieves a previously saved configuration), resuming the app after at least 30 minutes, and so forth. Sync is the primary communication with the back end through its Web API, of course, but the back end also provides an API for registering a user, retrieving an authenticated user’s settings, and updating those settings when an authenticated user changes the configuration.

Xamarin.Forms for a Cross-Platform Client

As you may have read in MSDN Magazine, Xamarin allows you to use C# and the Microsoft .NET Framework to build apps for Android, iOS and Windows, with a large amount of code that’s shared among platforms. (For an overview of our development configuration, see the later section, “Building with Xamarin on TFS and VSO.”) The Xamarin.Forms framework increases this amount further by providing a common UI solution for XAML/C#. With Xamarin.Forms, the Altostratus project shares more than 95 percent of its code in a single PCL. The only platform-­specific code in the project, in fact, are the bits for startup that come from the project templates, renderers for the login pages that deal with a Web browser control, and a few lines of code to copy the pre-populated SQLite database to the appropriate read-write location in local storage.

Note that a Xamarin project can also be configured to use a shared project rather than a PCL. However, Xamarin recommends using a PCL, and a primary benefit with Altostratus is we use the same PCL in a Win32 console application to create the pre-populated database. This means we don’t duplicate any database code for this purpose, and the initializer program will always be in sync with the rest of the app.

Be mindful that shared code doesn’t much reduce the effort needed to thoroughly test the app on each target platform; that part of your process will take about as long as it would if you wrote each app natively. Also, because Xamarin.Forms is quite new, you may find platform-specific bugs or other behaviors that you’ll need to handle in your code. For details on a few we found when writing Altostratus, see our post at bit.ly/1g5EF4j.

If you run into strange issues, your first stop should be the Xamarin bug database (bugzilla.xamarin.com). If you don’t see your issue discussed there, post your question or issue on the Xamarin Forums (forums.xamarin.com), where you’ll find the Xamarin staff to be quite responsive.

That said, dealing with individual issues like these is far less work than learning the details of each individual platform’s UI layer. And because Xamarin.Forms is relatively new, finding such issues helps the framework become increasingly robust.

Platform-Specific Adjustments

Within Xamarin.Forms, it’s sometimes necessary to make adjustments for one platform or another, such as fine-tuning the layout. (Refer to Charles Petzold’s excellent book, “Programming Mobile Apps with Xamarin.Forms” [bit.ly/1H8b2q6], for a number of examples.) You might also need to handle some behavioral inconsistencies, such as when a webview element fires its first Navigating event (again, for a few we encountered, see our post at bit.ly/1g5EF4j).

For this purpose, Xamarin.Forms has an API Device.OnPlatform<T>(iOS_value, Android_value, Windows_value), and a matching XAML element. As you can guess, OnPlatform returns a different value depending on the current runtime. For example, the following XAML code hides the Configuration page’s login controls on Windows Phone because the Xamarin.Auth component doesn’t yet support that platform, so we always run unauthenticated (configuration.xaml):

<StackLayout Orientation="Vertical">
  <StackLayout.IsVisible>
    <OnPlatform x:TypeArguments="x:Boolean" Android="true" iOS="true"
      WinPhone="false" />
  </StackLayout.IsVisible>
  <Label Text="{ Binding AuthenticationMessage }" FontSize="Medium" />
  <Picker x:Name="providerPicker" Title="{ Binding ProviderListLabel }"
    IsVisible="{ Binding ProviderListVisible }" />
  <Button Text="{ Binding LoginButtonLabel}" Clicked="LoginTapped" />
</StackLayout>

Speaking of components, Xamarin itself is primarily built of components that abstract common capabilities of the native platforms, many of which predate Xamarin.Forms for UI. Some of these components are built into Xamarin, whereas others, including community contributions, you acquire from components.xamarin.com. In addition to Xamarin.Auth, Altostratus uses the Connectivity Plugin (tinyurl.com/xconplugin) to show an indicator and disable the refresh button when the device is offline.

We found there’s always some lag between when connectivity changes on the device (reflected in the plug-in’s IsConnected property) and when the plug-in fires its event. This means there can be a few seconds between the device going offline and the Refresh button changing to the disabled state. To handle this, we use the Refresh command event to check the plug-in’s IsConnected status. If it’s offline, we immediately disable the button, but set a flag that tells the ConnectivityChanged handler to automatically start a sync when connectivity is restored.

Altostratus also uses Xamarin.Auth (tinyurl.com/xamauth) to handle details of authentication through OAuth, which we’ll discuss in a moment. The caveat here is that the component presently supports only iOS and Android and not Windows Phone, and it wasn’t in scope for our project to solve that particular shortcoming. Fortunately, the client app runs just fine unauthenticated, which simply means that the user’s settings aren’t maintained in the cloud and data exchange with the back end isn’t fully optimized. When the component gets updated to support Windows, we need only remove the OnPlatform tag in the XAML shown earlier to make the login controls visible.

Authentication with the Back End

In the Altostratus application as a whole, we wanted to demonstrate the mechanics involved in storing some user-specific preferences on the back end such that the back end could automatically apply those preferences when handling HTTP requests. For this specific application, of course, we could have achieved the same result using just URI parameters with the requests, but such an example wouldn’t serve as a basis for more complex scenarios. Storing preferences on the server also allows them to roam across all the user’s devices.

To work with any kind of user-specific data means authen­ticating that unique user. This is different, mind you, from authorization. Authentication is a way to identify a user and validate they are who they claim to be. Authorization, on the other hand, relates to the permissions that any particular user has (for example, admin versus regular user versus guest).

For authentication, we use social login through third parties such as Google and Facebook, rather than implement our own credential system (and the back end has an API through which the client app retrieves a provider list for the Configuration page UI). The primary advantage to social login is that we don’t have to deal with credentials at all, or their attendant security and privacy concerns; the back end stores only an e-mail address as the user name, and the client manages only an access token at run time. Otherwise the provider does all the heavy lifting, including e-mail verification, password retrieval and so on.

Of course, not everyone has an account with a social login provider, and some users don’t want to use social media accounts for privacy reasons. Also, social login may not be appropriate for line-of-business apps; for such cases we recommend Azure Active Directory. For our purposes, however, it’s a logical choice because we simply need some means to authenticate an individual user.

Once authenticated, a user is authorized to save preferences on the back end. If we wanted to implement other levels of authorization (such as modifying other users’ preferences), the back end could check the username against a permissions database.

Using OAuth2 for Social Login in ASP.NET Web API OAuth2 (bit.ly/1SxC1AM) is an authorization framework  that allows users to grant access to resources, without sharing their credentials. It defines several “credential flows” that specify how credentials are passed around among various entities. ASP.NET Web API uses the so-called “implicit grant flow” in which the mobile app neither collects credentials nor stores any secrets. That work is done by the OAuth2 provider and the ASP.NET Identity library (asp.net/identity), respectively.

To enable social login, you must register your application with each of the login providers through their developer portals. (An “application” in this context means all client experiences, including mobile and Web, and isn’t specifically tied to a mobile app). Once registered, the provider gives you a unique client ID and secret. See bit.ly/1BniZ89 for some examples.

We use these values to initialize the ASP.NET Identity middleware, as shown in Figure 3.

Figure 3 Initializing the ASP.NET Identity Middleware

var fbOpts = new FacebookAuthenticationOptions
{
  AppId = ConfigurationManager.AppSettings["FB_AppId"],
  AppSecret = ConfigurationManager.AppSettings["FB_AppSecret"]
};
fbOpts.Scope.Add("email");
app.UseFacebookAuthentication(fbOpts);
var googleOptions = new GoogleOAuth2AuthenticationOptions()
{
  ClientId = ConfigurationManager.AppSettings["GoogleClientID"],
  ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"]
};
app.UseGoogleAuthentication(googleOptions);

The strings like “FB_AppID” are keys that refer to the Web app’s environment and config settings, where the actual IDs and secrets are stored. This gives you the ability to update them without rebuilding and redeploying the app.

Using Xamarin.Auth to Handle Credential FlowOverall, the process of social authentication involves a variety of handshakes between the app, the back end and the provider. Fortunately, the Xamarin.Auth component (available in the Xamarin component store), handles most of this for the app. This includes working with the browser control and providing callback hooks so the app can respond when the authorization is complete.

Out of the box, Xamarin.Auth has the client app perform some parts of the authorization dance, which means the app stores the client ID and secret. That’s slightly different from the ASP.NET flow, but Xamarin.Auth has a well-factored class hierarchy. The Xamarin.Auth.O­Auth2Authenticator class derives from WebRedirectAuthenticator, which gives us the base functionality we need and requires us to write only a small amount of additional code, which is found in the LoginPageRenderer.cs files in the Android and iOS projects (because Xamarin.Auth doesn’t yet support Windows). For more details on what we do here, see our blog post at tinyurl.com/kboathalto.

The client app, then, simply has a LoginPage class that derives from the base ContentPage of Xamarin.Forms, allowing us to navigate there. This class exposes two methods, CompleteLoginAsync, and CancelAsync, which are called from the LoginPageRenderer code depending on what the user does in the provider’s Web interface.

Sending Authenticated Requests After a successful login, the client app has an access token. To make an authenticated request, it simply includes that token in an Authorization header like this:

GET https://hostname/api/UserPreferences HTTP/1.1
Authorization: Bearer I6zW8Dk...
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko

Here, "Bearer" indicates authorization using bearer tokens, after which comes the long, opaque token string.

We use the System.Net.Http.HttpClient library for all REST requests with a custom message handler to add the authentication header to each request. Message handlers are plug-in components that allow you to examine and modify the HTTP request and response messages. To learn more, see bit.ly/1MyMMB8.

The message handler is implemented in the class Authentication­MessageHandler (webapi.cs), and is installed when creating the HttpClient instance:

_httpClient = HttpClientFactory.Create(
  handler, new AuthenticationMessageHandler(provider));

The ITokenProvider interface is just a way for the handler to get the access token from the app (this is implemented in the UserPreferences class in model.cs). The SendAsync method is called for every HTTP request; as Figure 4 shows, it will add the Authorization header if the token provider has one to use.

Figure 4 Adding the Authorization Header

public interface ITokenProvider
{
  string AccessToken { get; }
}
class AuthenticationMessageHandler : DelegatingHandler
{
  ITokenProvider _provider;
  public AuthenticationMessageHandler(ITokenProvider provider)
  {
     _provider = provider;
  }
  protected override Task<HttpResponseMessage>
    SendAsync(HttpRequestMessage request,
    System.Threading.CancellationToken cancellationToken)
  {
    var token = _provider.AccessToken;
    if (!String.IsNullOrEmpty(token))
    {
      request.Headers.Authorization =
        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }
    return base.SendAsync(request, cancellationToken);
  }
}

On the back end, as described in Part 1 of this article, if a token is received with a request, the token is used to retrieve that user’s preferences and apply them automatically to the rest of the request. For example, if the user has set the conversation limit to 25 instead of the default of 100, then a maximum of 25 items will be returned with a request, saving network bandwidth.

Building an Offline Cache for Back-End Data

A big advantage of a mobile app over the mobile Web is the flexibility to support offline usage. A mobile app, by definition, is always present on the user’s device and can use a variety of data storage options, such as SQLite, to maintain an offline data cache, rather than relying on browser-based mechanisms.

The UI of the Altostratus mobile client, in fact, simply works with data that’s maintained in a local SQLite database, making the app fully functional without connectivity. When connectivity is present, background processes retrieve current data from the back end to update the database. This updates the data model objects that sit above the database, which in turn triggers UI updates through data binding (you can see this back in Figure 2). In this way it’s a very similar architecture to the back end discussed in Part 1, where the ongoing webjobs collect, normalize and store data in a SQL Server database so that the Web API can service requests directly from that database.

Offline support for Altostratus involves three distinct tasks:

  • Placing a pre-populated database file directly in the app package to provide working data immediately on first run without requiring connectivity.
  • Implementing one-way synchronization processes for each part of the data model that gets surfaced in the UI: conversations (items), categories, authentication providers and user preferences.
  • Hooking up synchronization to appropriate triggers beyond the Refresh button in the UI.

Let’s look at each of these in turn.

Creating a Prepopulated Database It’s possible for a user to install an app from an online store but not run it until a later time when the device is offline. The question is, do you want your app to say, “Sorry, we can’t do anything useful unless you’re online?” Or do you want your app to handle such cases intelligently?

To demonstrate the latter approach, the Altostratus client includes a prepopulated SQLite database directly in its app package on each platform (located in each platform project’s resources/raw folder). On first run, the client copies this database file to a read-write location on the device and then works with it from there exclusively. Because the file copy process is unique to each platform, we use the Xamarin.Forms.DependencyService feature to resolve, at runtime, a specific implementation of an interface we define called ISQLite. This happens from the DataAccessLayer constructor (DataAccess.cs), which then calls ISQLite.GetDatabasePath to retrieve the platform-specific location of the copied read-write database file, as shown in Figure 5.

Figure 5 Retrieving the Platform-Specific Location of the Database File

public DataAccessLayer(SQLiteAsyncConnection db = null)
{
  if (db == null)
  {
    String path = DependencyService.Get<ISQLite>().GetDatabasePath();
    db = new SQLiteAsyncConnection(path);               
    // Alternate use to use the synchronous SQLite API:
    // database = SQLiteConnection(path);               
  }
  database = db;
  _current = this;
}

To create the initial database, the Altostratus solution contains a small Win32 console application called DBInitialize. It uses the same shared PCL as the app to work with the database, so there’s never an issue of having a second, mismatched code base. DBInitialize, however, doesn’t need to use the DependencyService: It can just create a file directly and open a connection:

string path = "Altostratus.db3";
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(path);
var dbInit = new DataAccessLayer(conn);

From here, DBInitialize calls DataAccessLayer.InitAsync to create the tables (something the app never has to do with the prepopulated database), and uses the other DataAccessLayer methods to get data from the back end. Note that with async calls, DBInitialize just uses .Wait; because it’s a console application and doesn’t need to worry about responsive UI:

DataModel model = new DataModel(dbInit);
model.InitAsync().Wait();
model.SyncCategories().Wait();
model.SyncAuthProviders().Wait();
model.SyncItems().Wait();

To give users something to look at, it uses a timer to put a dot on the screen every half-second.

Note that you’ll always want to check the prepopulated database with a tool like DB Browser for SQLite (bit.ly/1OCkm8Y) before pulling it into the project. It’s possible for one or more of the Web requests to fail, in which case the database wouldn’t be valid. You could build this logic into DBInitialize so it deletes the database and shows an error. In our case, we just watch for error messages and run the program again, if needed.

You might be asking, “Won’t the contents of a prepopulated database go out of date relatively quickly? I wouldn’t want the users of my app to see really stale data on first run!” This will, of course, be the case if you don’t regularly update your app. So you’ll want to commit to periodic app updates that include a database with reasonably current data (depending on the nature of your data).

If the user already has the app installed, the update won’t have any affect because the code that copies the packaged database file checks whether a read-write copy already exists, and just uses that. However, if file existence was the only such check, a user who hasn’t run the app for a while could end up launching the app with older data than what’s actually in a more recently updated package. You could check whether the timestamp of the cache database is older than the in-package one, and overwrite the cache with the newer copy. This isn’t something we implemented in Altostratus, however, because we’d also need to preserve the user preferences information from the existing database.

Synchronizing the Offline Cache with the Back End As noted before, the Altostratus client always runs against its cache database. All Web requests to the back end (except for uploading new user preferences) happen in the context of synchronizing the cache. The mechanism for this is implemented as part of the DataModel class, specifically through the four methods in sync.cs: SyncSettings (which delegates to Configuration.ApplyBack endConfiguration in model.cs), SyncCategories, SyncAuthProviders and SyncItems. Clearly the workhorse of the bunch is SyncItems, but we’ll talk about what triggers all of these in the next section.

Note that Altostratus synchronizes data in one direction only, from the back end to the local cache. Also, because we know that the data we’re interested in doesn’t change all that rapidly (given the schedule for the back-end webjobs), we care only about eventual consistency with the back-end data store rather than updating on the order of minutes or seconds.

Each sync process is essentially the same: Retrieve the current data from the back end, update the local database with new values, remove any old values from the database and then repopulate the data model objects to trigger UI updates.

For items, there’s a little more work because SyncItems can be invoked from the UI, and we want to guard against over-excited users who press the button repeatedly. The private DataModel.syncTask property indicates whether there’s an active item sync; SyncItems ignores a repeat request if syncTask is non-null. Furthermore, because an item request might take a while and involves larger data sets, we want to be able to cancel an item sync if the device goes offline. To do so, we save a System.Threading.CancellationToken for the task.

The private SyncItemsCore method, shown in Figure 6, is the heart of the process. It retrieves the timestamp of the last sync from the database and includes that with the Web request.

Figure 6 The Private SyncItemsCore Method

private async Task<SyncResult> SyncItemsCore()
{
  SyncResult result = SyncResult.Success;
  HttpResponseMessage response;
  Timestamp t = await DataAccessLayer.Current.GetTimestampAsync();
  String newRequestTimestamp =
    DateTime.UtcNow.ToString(WebAPIConstants.ItemsFeedTimestampFormat);
  response = await WebAPI.GetItems(t, syncToken);
  if (!response.IsSuccessStatusCode)
  {
    return SyncResult.Failed;
  }
  t = new Timestamp() { Stamp = newRequestTimestamp };
  await DataAccessLayer.Current.SetTimestampAsync(t);
  if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
  {
    return SyncResult.NoContent;
  }
  var items = await response.Content.ReadAsAsync<IEnumerable<FeedItem>>();
  await ProcessItems(items);
  // Sync is done, refresh the ListView data source.
  await PopulateGroupedItemsFromDB();
  return result;
}

By doing this, the back end returns only those items that are new or updated since the given time. As a result, the client gets only the data it really needs, conserving the user’s potentially limited data plan. This also means the client does less work to process data from each request, which also conserves battery power and minimizes network traffic. Though it doesn’t sound like much, handling five conversations per category instead of, say, 50, with each request is a 90 percent reduction. At 20 to 30 syncs per day, this could easily add up to hundreds of megabytes in a month for just the one app. In short, your customers will certainly appreciate the efforts you make to optimize the traffic!

Once the request comes back, the ProcessItems method adds all those items to the database, doing a little cleanup of titles (such as removing smart quotes) and extracting the first 100 characters of the body for a description to show in the main list. The title cleanup is something we could have the back end do instead, which might save just a little processing time on the client. We’ve chosen to leave it on the client because other scenarios might need to do platform-­specific adjustments. We could also have the back end create the 100-character descriptions, which would mean saving a little client processing but increasing the network traffic. With the data we’re working with here, it’s probably an even trade-off, and because the UI is ultimately the client’s responsibility, it seems better to leave the client in control of this step. (For additional details on this and a couple other UI considerations, see our blog post tinyurl.com/kboathaltoxtra.)

Once we’ve added items to the database, the data model groups are refreshed through PopulateGroupedItemsFromDB. Here it’s important to understand that the database probably has more items than necessary for the user’s current conversation-limit setting. PopulateGroupedItemsFromDB accounts for this by applying that limit directly to the database query.

Over time, though, we don’t want the database to keep expanding by retaining a bunch of items that will never be displayed again. For this, SyncItems calls a method DataAccessLayer.ApplyConversationLimit to cull old items from the database until the number of items matches a specified limit. Because the size of any individual item within the Altostratus data set is relatively small, we use the maximum conversation limit of 100 regardless of the user’s current setting. This way, if the user raises that limit, we don’t have to request data again from the back end. If we had much larger data items, however, it might make more sense to aggressively cull the database and request items again if they’re needed.

Synchronization Triggers The Refresh button in the UI is clearly the primary way an item sync happens, but when do the other sync processes take place? And are there other triggers for an item sync?

It’s a bit tricky to answer these questions with regard to the code, because all calls to the Sync* methods happen in one place, the HomeViewModel.Sync method. However, this method, and a secondary entry point, HomeViewModel.CheckTimeAndSync, are called from a variety of other places. Here’s a summary of when, where and how calls to Sync are parameterized with a value from the SyncExtent enumeration:

  • On startup, the HomeViewModel constructor calls Sync(SyncExtent.All), using a fire-and-forget pattern so the sync happens entirely in the background. The pattern here simply means saving the return value from an async method into a local variable to suppress a compiler warning about not using await.
  • Inside the handler for the Connectivity plug-in’s ConnectivityChanged event, we call Sync if the device was offline when a previous call was made (using the same extent as requested then).
  • If the user visits the Configuration page and makes changes to the active categories or the conversation limit, or logs into the back end and, thus, applies settings from the back end, that fact is remembered by the DataModel.Configuration.HasChanged flag. When the user returns to the homepage, the HomePage.OnAppearing handler calls HomeViewModel.CheckRefresh, which checks HasChanged and calls Sync(SyncExtent.Items), if needed.
  • The App.OnResume event (app.cs) calls CheckTimeAndSync, which applies some logic to determine what should be synced based on how long the app has been suspended. Clearly, these conditions are highly dependent on the nature of your data and back-end operations.
  • Finally, the Refresh button calls CheckTimeAndSync with a flag to always do at least an item sync. The Refresh button uses CheckTimeAndSync because it’s possible—albeit quite rare—that a user might have left the app running in the foreground for more than half an hour or even a day, in which case the Refresh button should also do the other syncs as we do when resuming.

A benefit of consolidating everything into HomeViewModel.Sync is that it can set the public HomeViewModel.IsSyncing property at the appropriate times. This property is data-bound to both the IsVisible and IsRunning properties of a Xamarin.Forms.ActivityIndicator in Home.xaml. The simple act of setting this flag controls the visibility of that indicator.

Building with Xamarin on TFS and Visual Studio Online

For the Altostratus project, we used a development environment that’s somewhat common for cross-platform work: a Windows PC with emulators and tethered devices for Android and Windows Phone, along with a local Mac OS X machine with the iOS simulator and tethered iOS devices (see Figure 7). With such a setup, you can do all development and debugging work directly within Visual Studio on the PC, using the Mac OS X machine for remote iOS builds and debugging. Store-ready iOS apps can then also be submitted from the Mac.

A Common Cross-Platform Development Environment for Xamarin Projects, As Well As Those That Use Other Technologies Like Visual Studio Tools for Apache Cordova
Figure 7 A Common Cross-Platform Development Environment for Xamarin Projects, As Well As Those That Use Other Technologies Like Visual Studio Tools for Apache Cordova

We employed Visual Studio Online for team collaboration and source control, and configured it to do continuous integration builds for both the back end and the Xamarin client. Had we started this project today, we’d be able to use the latest Visual Studio Online build system to build Xamarin apps directly in the hosted build controller. You can find out more from our blog post at tinyurl.com/kboauthxamvso. Earlier in 2015, however, the hosted build controller didn’t yet have this support. Fortunately, it’s a simple matter—honestly!—to use a local machine running TFS as the build controller for Visual Studio Online. On that server we installed the free TFS Express edition along with Xamarin and the necessary Android and Windows platform SDKs, making sure to place the Android SDK in a location such as c:\android-sdk, which the build account could access. (Its installer by default places the SDK in the current user’s storage, to which the build account doesn’t have permissions.) This is discussed in the Xamarin documentation, “Configuring Team Foundation Server for Xamarin,” at bit.ly/1OhQPSW.

Once the build server is fully configured, the following steps make the connection to Visual Studio Online (see “Deploy and Configure a Build Server” at bit.ly/1RJS4QL):

  1. Open the TFS Administration Console.
  2. In the left-hand navigation pane, expand the server name and select Build Configuration.
  3. Under the build service, click Properties to open the Build Service Properties dialog.
  4. Click “Stop the service” at the top of the dialog.
  5. Under Communications, in the box under Provide Build Services for Project Collection, enter the URL of your Visual Studio Online collection, such as https://<your account>.visualstudio.com/defaultcollection.
  6. Click the Start button at the bottom of the dialog to restart the service.

That’s all it takes! When you create a build definition in Visual Studio Team Explorer, the TFS machine connected to Visual Studio Online will appear in the list of available build controllers. By selecting that option, builds that you queue from Visual Studio or that are queued upon check-in will be routed to your TFS machine.

Wrapping Up

We hope you’ve enjoyed our discussion on the Altostratus project, and that you’ll find the code useful for your own mobile, cloud-connected apps. Our goal with this project, again, was to provide a clear example of a cross-platform mobile app with a custom back end that could do significant work on behalf of the client to optimize the work that had to be done on the client directly. By having the always-running back end collect data on behalf of all clients, we greatly reduced the amount of client-generated network traffic (and its subsequent impact on data plans). By normalizing the data from different sources, we minimized the amount of data processing necessary on the client, which conserves ever-important battery power. And by authenticating a user with the back end, we demonstrated how it’s possible to store user preferences there and have them automatically applied to the client’s interactions with the back end, again optimizing network traffic and processing requirements. We understood that for our specific requirements there might have been easier ways to achieve the same effect, but we wanted to create an example that would be scalable to more complex scenarios.

We’d love to hear what you think about this project. Let us know!

Azure Offline Sync

An alternative to implementing your own offline cache is Azure Offline Sync for tables, which is part of Azure Mobile Services. This eliminates the need to write any sync code at all, and works for pushing changes from the client to the server. Because it uses table storage, however, it doesn’t provide a relational data model as SQLite does.


Kraig Brockschmidt works as a senior content developer for Microsoft and is focused on cross-platform mobile apps. He’s the author of “Programming Windows Store Apps with HTML, CSS and JavaScript” (two editions) from Microsoft Press and blogs on kraigbrockschmidt.com.

Mike Wasson is a content developer at Microsoft. For many years he documented the Win32 multimedia APIs. He currently writes about Microsoft Azure and ASP.NET.

Rick Anderson works as a senior programming writer for Microsoft, focusing on ASP.NET MVC, Microsoft Azure and Entity Framework. You can follow him on Twitter at twitter.com/RickAndMSFT.

Erik Reitan is a senior content developer at Microsoft. He focuses on Microsoft Azure and ASP.NET. Follow him on Twitter at twitter.com/ReitanErik.

Tom Dykstra is a senior content developer at Microsoft, focusing on Microsoft Azure and ASP.NET.

Thanks to the following technical experts for reviewing this article: Michael Collier, Brady Gaster, John de Havilland, Ryan Jones, Vijay Ramakrishnan and Pranav Rastogi