Cross-Platform Apps with Xamarin Forms and Azure Mobile Services

By July 14, 2014Xamarin

Inspired by Jesse Liberty’s fantastic blog series on learning Xamarin Forms, I decided to explore developing a fully cross-platform app of my own using Xamarin Forms. I thought it would be useful to explore how I can leverage Azure Mobile Services within the app to create a unified experience for a user regardless of which device they use, and allow their data to travel with them.

For this app, I’ve chose to resurrect the very first app I ever developed, Rebate Reminder. I wrote this app YEARS ago when  was first starting out as a developer, and was an old Windows Forms VB app I wrote in .NET 1.1! I promised myself I would revisit it and make a REAL app of it someday, and it looks like that time is now!

Creating the Project

Since Jesse has already done a great job talking about the basics of developing with Xamarin Forms, I’ll skip describing the creation of all the different screens. Of course, the full source code is available if you want to see how the project works, and if you have any questions about the project itself that you’d like to see in more detail, please sound off in the comments. I’ll gladly follow-up with additional posts if there is interest.

The app consists of a few Form views, including a Stores List, Rebates List, and screens to add or edit each type. Here’s a preview of the app on the different platforms:

Xamarin-Azure-Mobile-Services-Android-Stores-View Xamarin-Azure-Mobile-Services-Windows-Stores-View Xamarin-Azure-Mobile-Services-iOS-Stores-View
Xamarin-Azure-Mobile-Services-Android-Add-Store-View Xamarin-Azure-Mobile-Services-Windows-Phone-Add-Store-View Xamarin-Azure-Mobile-Services-iOS-Add-Store-View

You may notice that the Windows Phone version is missing the Page Title. This appears to be a limitation of the Xamarin Forms implementation, and I’ll describe how I worked around it in the next post.

For now, let’s proceed to setting up Azure so we can start saving data.

Setup Azure Mobile Services

Microsoft Azure makes it pretty simple to get started; all I needed to do was create a new Mobile Service instance:

Xamarin-Azure-Create-Mobile-Service

Once that was created I could add the two tables I needed for my app: Store and Rebate:

Xamarin-Azure-Mobile-Service-Tables

Because Azure supports dynamic schema, the columns will automatically be created and populated with data when we push content to the service. Be sure of course, that you have this property enabled in the Configuration tab of your Azure service:

Xamarin-Azure-Mobile-Service-Dynamic-Schema

That’s all we need to move to the next step, but for a more detailed walkthrough the process of setting up Azure for use by Xamarin, take a look at this helpful guide: Get started with Mobile Services.

Reference Mobile Services and Create a Client

Fortunately, this step is also easy, as everything you need to add Mobile Services to an app is available via nuget for all supported Xamarin platforms. Simply install the Azure Mobile Services nuget package to all three versions of the app, as well as the shared project.

Xamarin-Azure-Mobile-Services-Nuget

This makes the MobileServiceClient available for use across all of the platforms. There are several strategies you can use to define and use the client across your platforms, but to keep things simple I created a static reference in the project App definition, which as we will see later, I pass into each ViewModel as it is created.

Here’s a sample of the code; if you download the source be sure and replace the keys to match your own service.

public class App
{
public const string applicationURL = @”URL_TO_AZURE_SERVICE”;
public const string applicationKey = @”AZURE_API_KEY”;
public static MobileServiceClient client = new MobileServiceClient(applicationURL, applicationKey); 

public static Page GetMainPage()
{
var mainPage = new StoresView();
return new NavigationPage(mainPage);
}
}

Now that we have a client connection, we can proceed to use it to work with the app data.

Saving and Retrieving Data

This too ended up being a simple task of creating the POCO definitions for Store and Table, and use them to pass data through the client to Azure.

I do this by initializing each ViewModel and passing in the static client through the constructor. I realize this isn’t exactly the best way and probably not even necessary since I could simply reference the static object directly; I will likely refactor this in a future version. However, for the purposes of this sample it gets the job done:

Here’s a sample of the StoresView initializing its ViewModel with the client:

public StoresView()
{
InitializeComponent();
 

this.ViewModel = new StoresViewModel(App.client);storeList.ItemSelected += storeList_ItemSelected;

btnAdd.Clicked += btnAdd_Clicked;
}

Now we can proceed to use this client to add a new store. In this screenshot below, a new Store object instance is bound to backing ViewModel:

Xamarin-Azure-Mobile-Services-Add-Item

The updated values are saved to the object, and on submit, are posted to Azure using the client, as shown in this code sample:

private async Task ExecuteAddEditCommand()
{
try
{
var stores = client.GetTable<Store>();
if (CurrentStore.Id == Guid.Empty)
{
await stores.InsertAsync(CurrentStore);
}
else
await
stores.UpdateAsync(CurrentStore);
}
catch (Exception ex)
{
var page = new ContentPage();
var result = page.DisplayAlert(“Error”, “Error saving data. Please check connectivity and try again.”, “OK”, null);
}
}

Note that I’m checking to see if the Id is an empty Guid (which represents a new Store) and use the appropriate method to save the changes. Adding and editing rebates is handled similarly, and for more details, take a look at the available source code download.

Now that there is data in the Store table, we can proceed to reload the initial Stores view, which simply queries Azure using the given type, as shown here:

private async Task ExecuteLoadItemsCommand()
{
try
{
var stores = await client.GetTable<Store>().ToListAsync();

Stores.Clear();
foreach (var store in stores)
{
Stores.Add(store);
}
}
catch (Exception ex)
{
var page = new ContentPage();
var result = page.DisplayAlert(“Error”, “Error loading data. Please check connectivity and try again.”, “OK”, null);
}
}

The list on the Rebate view is handled similarly, except we also include in the query a Where clause to filter only the items that match the given Store Id:

private async Task ExecuteLoadItemsCommand()
{

try
{
var rebates = await client.GetTable<Rebate>().Where(r => r.StoreID.ToString() == SelectedStore.Id.ToString()).ToListAsync();

Rebates.Clear();
foreach (var rebate in rebates)
{
Rebates.Add(rebate);
}
}
catch (Exception ex)
{
var page = new ContentPage();
var result = page.DisplayAlert(“Error”, “Error loading data. Please check connectivity and try again.”, “OK”, null);
}
}

Note that because the actual data type of the Id column in Azure is a string, we need to convert the Guid to string when comparing. Attempting to search against the Guid property directly will result in an error similar to this:

Error: Invalid query specified. Error: ‘)’ or operator expected (at index 16)

Finally, deleting either a Store or a Rebate is as simple as passing the instance to the DeleteAsync method:

private async Task ExecuteDeleteStoreCommand()
{
try
{
var stores = client.GetTable<Store>();
await stores.DeleteAsync(SelectedStore);
}
catch (Exception ex)
{
var page = new ContentPage();
var result = page.DisplayAlert(“Error”, “Error deleting data. Please check connectivity and try again.”, “OK”, null);
}
}

And that completes this simple but functioning app to store and retrieve rebates that works against all three mobile platforms supported by Xamarin!

Next Steps

With the help of Xamarin Forms and Azure Mobile Services we were able to quickly create a cross-platform app to store and manage data accessible on any device. To learn more about this app and how it works take a look at the source code:

Get the CODE!

Obviously we still have much work to do to make this app “fully” functional. Clearly there is not yet any way to restrict the list of stores and rebates to a specific user, so anyone using the app will see the same data.

In addition, this app has many limitations that weaken the user experience. For example, there is no loading indicator to show that data is being fetched or saved. In addition, changes such as adding a store or rebate are not immediately reflected in the app, and require a restart or manual refresh of the current view.

We’ll tackle all of these, as well as the previously-mentioned issue with the Page Title on Windows Phone in the next few blog posts, so stay tuned for more!

In the meantime, let me know any questions in the comments and as always, I hope this was helpful!

The following two tabs change content below.
  • WHAMSY KRYSHNA

    How to implement authentication using Oauth and(or) ADAL for xamarin android app? I’m getting stuck with the redirect url. can u get me a clear solution for this?

  • Matt

    Awesome article, thanks!

    I’m trying to figure out if Mobile Services follows EF code-first guidelines – basically imagine you have a data structure that looks more like

    public class StoreGroup{
    public string ID{get;set;}
    public string Version{get;set;}
    pubic string Name{get;set;}
    public iEnumerable{get;set;}
    }

    public class Store{
    public string ID{get;set;}
    public string Version{get;set;}
    public string Name{get;set;}
    public IEnumerable{get;set;}
    }

    .. . . . etc. Would you need to define a mapping class for Mobile Services to understand the model, or can it deal with collections?

    • it’s been a while since i’ve looked at this last, but from what I recall at the time, while you could define the relationships in EF so that you can have navigation properties from parent to child collections, you were responsible for populating them yourself, either on demand, or better yet, via the cloud service. I recall that you could define custom JavaScript that would execute with each request to do things like populate navigation properties or cascade deletes and updates.

      These days I believe you can do this all on the server side too, but I don’t think it happens automatically via the EF navigation properties. I am hoping to spend some time on this in the coming weeks to learn more about what’s changed, and I’ll specifically keep your question in mind as I do, and I find out more, will update this thread. hope you do the same with what you find, thanks for reading

      -jm

      • Matt

        Thanks so much for the response! Sounds in that case like I’m better sticking with my NoSQL solution for now, and possibly migrating to Mobile Services using MongoDB at some point.