Chapter 5

Application Data Storage

WHAT’S IN THIS CHAPTER?

  • Understanding common application storage scenarios
  • Using isolated storage on WP7
  • Using external storage

Application data comes from various sources, such as user-generated inputs, operating system data, data received from the Web, and application-produced data. Some of the application data is transient, and you don’t need to save it in persistent storage, such as a Secure Digital (SD) card or device memory, or to save it on the Web; but other data may need to be persisted either in local data storage or to the Web so the application can access it later. This chapter shows how to leverage local data storage on the device and cloud storage (data storage on the Web, accessed via web services) on WP7 to save persistent data. After reading this chapter, developers will be able to choose between local data storage and cloud storage to implement common data storage scenarios.

APPLICATION STORAGE ON MOBILE DEVICES

Generally, you have control over a few data storage design decisions when creating a mobile application:

  • Where to save the data
  • What format to save the data in
  • How data is shared between applications

Historically, mobile applications on major software platforms usually have saved data locally on the device. For example, on Windows Mobile devices an application can use the registry to save some application-specific settings and use filesystem APIs to save other data to either device memory or an SD card. The iPhone Operating System (iOS) and Android both provide APIs to save data locally and privately — only the application can access its data. As more applications start to embrace the cloud and web services, it becomes possible to push data to the cloud while keeping a local copy in a cache. Thus data synchronization becomes a critical issue. Cloud data storage is discussed in the “Saving Data to the Cloud” section later in this chapter.

Mobile applications normally support three kinds of data format: application-specific, structural, and settings and preferences. Application-specific data can appear within plain text or XML files, or an application can store data within special binary data files. Some applications rely on a local SQL database to save structure data and enable the use of SQL-like queries and data manipulation. In fact, most of today’s mobile software platforms including Android and iOS support SQLite (www.sqlite.org), a compact, lightweight relational-database engine.

Application data also includes settings and preferences set by a user. All major mobile software platforms, including WP7, provide some way to save these settings. This topic is discussed in the “Saving Settings in Isolated Storage” section of this chapter.

Data sharing across applications on the device varies on different software platforms. At one time there wasn’t any concept of an application sandbox as a design choice, so applications simply shared data among each other using either a file or traditional operating system Interprocess Communication (IPC) methods such as sockets, messages, shared memory, and so on.

image

An application sandbox refers to a system mechanism that isolates an application’s running process to restrict its access to the underlying system and other processes. For example, an application in a sandbox will not crash the whole operating system and cannot access data of other applications.

Today’s mobile applications are mostly isolated in their own runtime sandboxes on major software platforms as a means to enhance security and reliability of the system. In addition, both Android and iOS provide a cross-application data-sharing method for applications designed to serve data to other applications. Android addresses this issue with Content Provider, a special facility to enable one application to provide data for others. On iOS, an application can register a custom URL with the system and handle data-encoded custom URLs sent from other applications. Unfortunately, at the time of writing, WP7 does not provide an on-device cross-application data-sharing method, meaning that there is no way to directly access another application’s data on the same device.

On the other hand, developers can always use cloud storage and web services as a way to share data across applications on the same device and across devices. The “Saving Data to the Cloud” section of this chapter will discuss this further. In addition, all three major operating systems allow applications to access system data such as contact information, call information, calendars, and e-mails.

Local and Cloud

Mobile applications commonly combine local and cloud data as part of the data usage model. Sometimes this is the only viable approach, because the cloud data, such as RSS feeds, isn’t under the developer’s control.

When an application is running, it can store its data completely in memory when the data size isn’t too large. If the data becomes too large to store in memory, the application relies on persistent storage on the device. In both cases, the application can communicate with cloud storage or a web service provider to download the latest data, as well as upload updates to the cloud or web service. Communication of this sort generally requires a synchronization framework that developers can use to build both the device-side and cloud-side applications to ensure data consistency without worrying about a data connection and synchronization management. Data synchronization usually relies on version numbers or timestamps for each data item.

Android provides a synchronization service and a SyncAdapter class that developers can use to build data synchronization with cloud storage (the server). By extending the AbstractThreadedSyncAdapter class and implementing the onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult) method, the system’s sync service can perform the specified data sync operations. The device-side application must store its data in a Content Provider. On the server side, the application can store data in any structure as long as the client and the server can communicate effectively. Usually the application performs this task using a JavaScript Object Notation (JSON)–based web service (see Chapter 6 for details about using JSON).

iOS doesn’t provide a synchronization framework that developers can plug in to data-processing methods. In order to enable local and cloud synchronization, the developer must build everything from scratch, but the basic idea is the same as with Android: applications poll the server, using web service calls to obtain and cache data locally, as well as to update data on the server side. Device-side data is usually saved in a SQLite database or in XML files if the data isn’t too large.

On WP7, developers can leverage Microsoft’s Azure synchronization framework (www.microsoft.com/windowsazure) to handle data synchronization. The “Using Cloud Data Services” section of this chapter discusses use of Microsoft’s Azure.

Local Files and Databases

When an application has smaller data requirements (usually in the form of key-value pairs), all it really needs is a custom file or an XML file to save them. The application simply implements data serialization and de-serialization to and from the file.

iOS provides programming constructs such as NSMutableDictionary and NSArray to hold the data, and file system methods such as NSSearchPathForDirectoriesInDomains() and writeToFile() to read and write a file. You can parse XML files using the NSXMLParser class.

Android provides standard Java filesystem methods such as FileOutputStream() and FileInputStream() to access the application’s private storage. Developers can use the android.utils.Xml class or Simple API for XML (SAX) in the org.xml.sax namespace and the javax.xml.parsers namespace to parse XML files.

WP7 provides similar XML-based serialization and de-serialization classes as detailed in the “Using Isolated Storage” section of this chapter. In fact, these classes not only allow serialization and de-serialization of text strings and primitive types, but also .NET objects.

In addition to using custom files or XML files, using a SQL database engine is a natural choice for applications that employ a complex data model. The advantages of using a SQL database to store and access data are:

  • A database manages structured data and enables flexible access.
  • A database maintains consistent data with schemes and transactions.
  • Applications can leverage easy-to-use SQL commands to query and update data.
  • A database provides good query and update performance.
  • A database provides enhanced data security.

Both iOS and Android provide APIs to manipulate data in a SQLite database. For example, Android provides an android.database.sqlite package that includes such classes as SQLiteDatabase and SQLiteQueryBuild. Thus it can directly interact with a private database (accessible only from the application) using SQL commands. Note that the SQLite database created by an application is not accessible outside the application on Android.

On the other hand, iOS provides a list of SQLite functions to perform the same tasks. For example, the header file /usr/include/sqlite3.h includes declarations of functions such as sqlite3_open, sqlite3_execute(), and sqlite3_close(). In addition, sqlite3_prepare_v2() is the function to prepare a SQL statement, and sqllite3_step() is used to step through a record set.

WP7 did not provide a built-in SQL database engine at the time of this writing. Developers will have to use cloud storage that provides a database engine, or explore third-party solutions such as winphone7db (winphone7db.codeplex.com) or Perst Embedded Database (www.mcobject.com/perst_eval).

USING ISOLATED STORAGE

On WP7, each application has a private storage area in the device memory called isolated storage. Similar to common filesystem access, an application can create directories and files in its isolated storage and read data from those files, as well as delete them. The recommended approach to using isolated storage is building serialization and de-serialization capability into an application, making it easy to save and restore object collections.

image

WP7 does not allow an application to access the SD card on the device. This is different from Android, which provides APIs to enable read-and-write access to the SD card.

Where Is Isolated Storage?

Unlike Windows Mobile, WP7 does not provide common filesystem APIs to explore and access the underlying filesystem of the device. Instead, an application can access a piece of the filesystem only through the isolated storage APIs; it has no way to access the isolated storage used by other applications. Thus applications are completely isolated from each other with respect to data access, preventing malicious applications from accessing user data as well as system data. The same design philosophy has been adopted by iOS and Android.

Isolated Storage Structure

An application’s isolated storage is organized in the form of a regular directory structure, where the application can create directories and sub-directories, and files within these directories. The layout of the isolated storage is shown in Figure 5-1.

FIGURE 5-1: WP7 isolated storage

image

Isolated storage contains both application settings and application data. An application can save some application-specific setting data in local settings files, using APIs such as IsolatedStorageSettings.ApplicationSettings.Add() and IsolatedStorageSettings.ApplicationSettings.Save() in the IsolatedStorage namespace. The settings files are managed by the system, and applications do not need to open these files directly. An example of using local settings is shown later in this section.

Applications can create any directory structure in their isolated storage. The APIs in the IsolatedStorage namespace provide such common filesystem capabilities as:

  • Creating and deleting directories
  • Creating, opening, copying, and deleting files
  • Enumerating directories and files in the root directory
image

If an application is uninstalled from the device, the system wipes out its isolated storage. This includes all directories, files, and application settings.

WP7 doesn’t impose a quota on the size of an application’s isolated storage. However, Microsoft suggests that applications use the space only when needed and delete files when no longer needed. The system monitors the free storage space of the whole system, and prompts the user to delete files and applications when free space is below 10 percent of the available space.

Using Files in Isolated Storage

Common scenarios for using isolated storage include data access and application setting access. You gain this access by leveraging the classes in the System.IO.IsolatedStorage namespace. For example, the following code snippet shows how to open a file in the application’s isolated storage:

using System.IO; //FileMode and FileAccess modes
using System.IO.IsolatedStorage;
...
try
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        if(store.FileExists(fileName))
        {
            IsolatedStorageFileStream fs =
            store.OpenFile(fileName, System.IO.FileMode.Open, FileAccess.READ);
            //Perform file Read operations using fs.Read()
            fs.Close();
        }
        
    }
}
catch (IsolatedStorageException e)
{
    //Handle the exception
}

To create a file in isolated storage, you set the file mode parameter in the IsolatedStorageFile.OpenFile() method to either FileMode.CreateNew or FileMode.Create. The difference between those two file modes is that FileMode.CreateNew will throw an IsolatedStorageException when a file of the same name exists, whereas FileMode.Create will open the file of the same name if it exists and truncate it to a zero length, then return to the calling method. The snippet below shows how to create a new file even if a file of the same name exists:

using System.IO; //FileMode and FileAccess modes
using System.IO.IsolatedStorage;
...

try
{
   using (var store = IsolatedStorageFile.GetUserStoreForApplication())
   {
      IsolatedStorageFileStream fs =
          store.OpenFile(fileName, System.IO.FileMode.Create);
      //Perform file write operations using fs.Write()
      fs.Close();
   }
}
catch (IsolatedStorageException e)
{
   //Handle the exception
}

Data Serialization for Isolated Storage

Developers can certainly save application data to a file in isolated storage in a custom format. In this case, developers must implement a custom serialization method and de-serialization method. A better approach is to use the data serialization APIs provided by WP7 Silverlight. The System.Runtime.Serialization namespace contains a number of classes that can be used to serialize and de-serialize a CLR object or an object graph (a set of related objects) to a file or a file stream in XML format. The following steps are required to use the provided serialization and de-serialization capability:

  • Establish a data contract between the underlying XML serializer and the application’s data class. This is done by adding the [DataContract] and [DataMember] attributes to the data class definition.
  • Instantiate a DataContractSerializer object with the data class and file stream associated with the file, and call its ReadObject() and WriteObject() methods to perform serialization and de-serialization.

The sample application in this chapter uses a NoteEntry class to model the user’s data. The NoteEntry class consists of an int Id field, a string Text field, and a LastUpdateTime field of type DateTime. Listing 5-1 shows the NoteEntry class used for serialization.

image

The chapter provides the AppDataSample application that demonstrates the use of local data storage and cloud storage on WP7. Because the application requires a web service reference (which is provided by another sample project, SampleCloudStorage), its data model class is actually automatically generated by the IDE when you add the web service reference to the project.

Note that because the AppDataSample application is a bit complicated, this section will not be able to cover the complete step-by-step creation of this project. Readers are strongly encouraged to download and compile the application code from the book’s website and go through the section with the project loaded in IDE.

image
LISTING 5-1: An example of data class used for data serialization, AppDataSample AppDataSampleNotesData.cs
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.IO.IsolatedStorage;
...
[DataContract]
public class NoteEntry
{
    //"id" field
    private int id;
    [DataMember(Name = "id")]
    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    //"lastUpdateTime" field
    private DateTime lastUpdateTime;
    [DataMember(Name = "lastUpdateTime")]
    public DateTime LastUpdateTime
    {
        get { return lastUpdateTime; }
        set { lastUpdateTime = value; }
    }

    //"text" field
    private string text;
    [DataMember(Name = "text")]
    public string Text
{
        get { return text ?? ""; }
        set { text = value; }
    }
}

With the data contract in place, the application can easily serialize a list of NoteEntry objects into a file stream and de-serialize them back to a collection of such objects. Listing 5-2 shows an example of serialization and de-serialization for a list of NoteEntry objects.

image
LISTING 5-2: An example of data serialization, AppDataSampleAppDataSampleNotesData.cs
public class NotesData
{
    private static List<NoteEntry> noteList = new List<NoteEntry>();
    private static string fileName = "Notes.xml";

    public static IEnumerable<NoteEntry> GetBindingData()
    {
        return noteList;
    }

    public static void AddOneEntry(NoteEntry note)
    {
        if (note == null) return;
        note.Id = noteList.Count + 1; //Note id starts from 1
        noteList.Add(note);
    }
    public static void SaveToFile()
    {
        if (noteList.Count < 1) return;

        try
        {
           using (var store = IsolatedStorageFile.
              GetUserStoreForApplication())
           {
              IsolatedStorageFileStream fs =
                  store.OpenFile(fileName, System.IO.FileMode.Create);
              DataContractSerializer ser =
                  new DataContractSerializer(
                      typeof(List<NoteEntry>));
              ser.WriteObject(fs, noteList);
              fs.Close();
           }
        }
        catch (SerializationException serEx)
        {
           MessageBox.Show(serEx.Message);
        }
        catch (IsolatedStorageException e)
        {
           MessageBox.Show(e.Message);
        }
    }

    // Read all notes from file, refresh the in-memory list
    public static void ReadFromFile()
    {
        try
        {
            using (var store =
               IsolatedStorageFile.GetUserStoreForApplication())
            {
                if(store.FileExists(fileName))
                {
                    IsolatedStorageFileStream fs =
                    store.OpenFile(fileName,
                    FileMode.Open,
                    FileAccess.Read);

                    IEnumerator<NoteEntry> noteEnum =
                       noteList.GetEnumerator();
                    DataContractSerializer ser =
                        new DataContractSerializer(
                            typeof(List<NoteEntry>));
                    noteList = (List<NoteEntry>)ser.ReadObject(fs);
                    fs.Close();
                }

            }
        }
        catch (SerializationException serEx)
        {
           MessageBox.Show(serEx.Message);
        }
        catch (IsolatedStorageException e)
        {
            MessageBox.Show(e.Message);
        }
    }
}

The static list List<NoteEntry> noteList of the NotesData object contains both notes data retrieved from the application’s isolated storage when the application starts, and the user’s input data. The sample application performs de-serialization by calling ReadFromFile() to build the initial noteList from notes.xml in isolated storage. Once the user adds a new note, the code creates a new NoteEntry object and adds it to noteList. When the application is deactivated or stopped, noteList is de-serialized to the same data file in isolated storage.

Saving Settings in Isolated Storage

You can save application settings to isolated storage by using the IsolatedStorageSettings class. The IsolatedStorageSettings.ApplicationSetting property contains a dictionary object that applications can use to save key-value pairs. The following code snippet, excerpted from the AppDataSample project, shows how to save a key-value pair to isolated storage:

image
using System.IO.IsolatedStorage;
...
try
{
    var appSettings = IsolatedStorageSettings.ApplicationSettings;
    if (!appSettings.Contains(SyncSettingKey))
    {
        appSettings.Add(
            SyncSettingKey,
            SyncToCloudWhenSave);
    }
    else
    {
        appSettings[SyncSettingKey] = SyncToCloudWhenSave;
    }

    appSettings.Save();

    return true;
}
catch (Exception e)
{
    MessageBox.Show(e.Message);
    return false;
}

Code snippet AppDataSampleAppDataSampleAppSettings.cs

The code creates a key-value pair from SyncSettingKey (the key) and SyncToCloudWhenSave (the corresponding value). The sample application uses this key-value pair to hold a user setting. Adding the pair to isolated storage is as simple as adding it to the dictionary object. Note that the code must call the IsolatedStorageSettings.Save() method to save the in-memory IsolatedStorageSettings instance to device storage.

The following code snippet shows retrieving the same key-value pair from isolated storage:

image
using System.IO.IsolatedStorage;
...
try
{
    var appSettings = IsolatedStorageSettings.ApplicationSettings;
    if (!appSettings.Contains(SyncSettingKey))
    {
        return false;
    }
    else
    {
        return (bool)appSettings[SyncSettingKey];
    }
}
catch (Exception e)
{
    MessageBox.Show(e.Message);
    return false;
}

Code snippet AppDataSampleAppDataSampleAppSettings.cs

SAVING DATA TO THE CLOUD

Many mobile applications use cloud storage to save user data so the user won’t lose it even after the application is uninstalled from the device. There are also applications that allow multiple types of clients, such as a desktop application, a website, and device applications on various platforms, to access and manage the same data set. In both cases, developers must design a unified data model that all client applications use, and web services that provide access to the cloud storage.

Building a Cloud Data Service

Microsoft provides Windows Azure service as a cloud storage solution, but developers are free to choose any web service provider. This section discusses using the Windows Azure development environment to build, debug, and deploy cloud web services for WP7 applications quickly. You’ll also find that applications on other software platforms can use the web services you create.

image

Server-side development, such as building Windows Azure Services, requires knowledge of specialized tools to implement web service methods and related database operations. This section provides an overview of building a Windows Azure service for WP7 applications. However, interested readers should also review the documentation for the tools used to create the example. For more details, see http://www.microsoft.com/windowsazure/getstarted/.

Windows Azure Service

The first step towards building a Windows Azure cloud service is to download Windows Azure SDK and Tools for Visual Studio (http://www.microsoft.com/downloads/en/details.aspx?FamilyID=7a1089b6-4050-4307-86c4-9dadaa5ed018). Be sure you follow the instructions on the web page because there are other software products you have to install before using the Windows Azure SDK and tools. For example, for a basic setup, you need a copy of Visual Web Developer 2010 Express (development environment, downloadable at www.microsoft.com/express/Downloads/#Visual_Studio_2010_Express_Downloads) and SQL Server 2008 Express (database engine, downloadable at www.microsoft.com/express/Downloads/#SQL_Server_2008_R2_Express_Downloads) to complete the example. You can, of course, use the full version of Visual Studio and SQL Server for the same purpose.

The Windows Azure SDK and Tools installed in Visual Web Developer 2010 Express enables developers to build and debug web services locally by packaging and deploying web services directly to a built-in web server. When you’re ready to deploy the web service project, you must obtain a Windows Azure account and then use the Visual Web Developer 2010 Express tool to deploy the services to Windows Azure. (At the time of this writing, you could obtain a free trial of Windows Azure at http://www.microsoft.com/windowsazure/free-trial/ until June 30, 2011, and Microsoft will almost certainly extend the free trial beyond this point.)

image

You might see the following error message when you open the chapter’s cloud service sample in Visual Web Developer 2010 Express:

“SampleCloudService.ccproj cannot be opened because its project type (.ccproj) is not supported by this version of the application. To open it, please use a version that supports this type of project.”

Note that this is an issue with the Windows Azure Tools. To fix this problem, simply do a “devenv /resetSkipPkgs” on the command line. The online forum http://social.msdn.microsoft.com/Forums/en/windowsazure provides help for other issues with Windows Azure Tools.

Building a Windows Azure Service

To build a web service with cloud storage that a WP7 device application can use, create a “Windows Azure project” in Visual Web Developer 2010 Express by selecting “Cloud” under the Visual C# template list and “Windows Azure Project.” Next, when prompted with a list of .NET Framework Roles for the solution, add a “Windows Communication Foundation (WCF) Service Web Role” to the solution. The web role refers to different types of services that a Windows Azure project can offer. Once you perform these two steps, the IDE automatically creates a basic web service project, and the default web role project name is WCFServiceWebRole1.

The key components of a Windows Azure service project appear below, along with the automatically generated filenames:

  • Service interface: Defines the service contract. This component appears in IService1 in IService1.cs. Add those web service methods that you want to provide into this interface. If a data model (a composite type) is used on both the service side and the device side, you should add a data contract class to this file as well.
  • Service class: Implements the service methods. This appears in Service1.svc.cs for class Service1 that implements the service interface IService1).
  • Data folder: This is a folder named App_Data where data files or a SQL database can be created.

An example of a service interface, IMyNoteService, is shown below. This is the service interface that you’ll use when working with the sample project, SampleCloudService, in this chapter.

image
[ServiceContract]
public interface IMyNoteService
{
    [OperationContract]
    int PushNotesData(List<NoteEntry> listNote);

    [OperationContract]
    List<NoteEntry> PullNotesData();


    [OperationContract]
    int GetNoteCount();

    [OperationContract]
    int DiscardAll();
}

Code snippet CloudServiceSampleCloudServiceSampleIMyNoteService.cs

The methods listed in the IMyNoteService interface are those that a web service client can call to perform a specific operation. As can be seen in the next section, a WP7 application project in Visual Studio 2010 Express can call those methods just as it would call methods of a regular class in the project. The application gains this access by adding a web reference to the web service into the WP7 application project. Visual Studio 2010 Express automatically generates proxy classes for the referenced web services.

Now it’s time to discuss the server side in more detail. Visual Web Developer 2010 Express deploys the web service to a built-in web server running locally at 127.0.0.1 (the localhost). Once the service is successfully deployed, a web page is automatically launched to show the service URL, such as http://127.0.0.1:84/MyNoteService.svc. This URL is used in the device development environment to obtain a web reference and create the proxy classes.

Using Cloud Data Services

Use the following steps to add a service reference to a WP7 project:

1. Right-click the References entry in Solution Explorer and choose Add Service Reference from the context menu. The Add Service Reference dialog (Figure 5-2) will appear.

FIGURE 5-2: The Add Service Reference dialog to a project

image

2. Enter the service URL obtained from the service provider or from the service development environment. Then choose the desired service classes to generate. For example, the sample project AppDataDemo uses services provided by another sample project CloudStorageDemo. Figure 5-3 shows the service class MyNoteService and its operations that the AppDataDemo project chooses to use.

FIGURE 5-3: Select service references

image

3. Give the generated proxy classes a namespace name. The example uses <add specific information here> as a namespace name.

Once the IDE generates the proxy classes, it adds them to the Object Browser. For example, if the server-side service interface name is IMyNoteService and the service class name is MyNoteService, the client-side proxy class name is MyNoteServiceClient. There are also proxy classes that you use in asynchronous callback methods as parameters. All these classes are shown in the file reference.cs, which is automatically generated when you add the web service reference.

This chapter uses a custom web service that is dedicated to the example WP7 application. For consuming standard web services, such as those provided by Facebook and Twitter, please see Chapter 6.

Calling Azure Service Asynchronously

Web service calls in the service proxy classes are all performed using an asynchronous pattern. For example, if a web service call method is named PushNotesData as shown in the service contract on the server side, then in the WP7 IDE the service proxy class has two methods for this specific web service call: the PushNotesDataAsync() method that initiates the call, and a custom callback method that the system calls when the web service call completes.

The following code Listing 5-3 shows an example of calling PushNotesDataAsync() of the proxy class MyNoteServiceClient from within the sample WP7 application AppDataSample. Note the use of an asynchronous call pattern in this example.

image
LISTING 5-3: An example of data class used for data serialization, AppDataSample AppDataSampleNotesData.cs
public static void SaveAllToCloud()
{
    try
    {
        MyNoteServiceClient client =
                new MyNoteServiceClient();
        client.PushNotesDataCompleted +=
            new EventHandler<PushNotesDataCompletedEventArgs>
                (Client_PushCompleted);

        client.PushNotesDataAsync(
            NotesData.ToObservableCollection());

        // Always close the client.
        client.CloseAsync();
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
}

public static void Client_PushCompleted(
    object sender,
    PushNotesDataCompletedEventArgs e)
{
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.Message);
    }
    else
    {
        Debug.WriteLine("Data push succeeded");
    }
}

In the above example, the code doesn’t use the return value of the PushNotesData() web method. The web service does provide a return value as the PushNotesDataCompletedEventArgs object e, which is passed back to the callback method Client_PushCompleted().

Microsoft Sync Framework

One of the exciting capabilities of WP7 application development is the data synchronization framework provided with the Windows Azure cloud service. The rationale behind providing this capability is quite simple; in contrast to Apple and Google, Microsoft has a large product line that offers complete software and service for the three screens that most developers work with today: desktop, mobile, and web. Each of these screens is powered by Microsoft database products and programming facilities such as Silverlight and WCF.

For a WP7 application that requires a server data store, the Windows Azure web service platform provides SQL Azure (http://msdn.microsoft.com/en-us/library/gg521148.aspx), a cloud-based relational database built on top of Microsoft SQL Server technologies. In addition, Microsoft provides Sync Framework that enables easy data synchronization between a WP7 Silverlight application and a SQL Azure instance.

The Microsoft Sync Framework adopts the Open Data (OData) standard and the OData Sync protocol for data exchange between a sync client and the sync end points in the cloud. The Sync Framework provides APIs that enable data conversion between a wide range of data sources (XML, JSON, etc.) and OData. The basic model of data synchronization on WP7 consists of the following components and relationships:

  • On the device: Application data in isolated storage
  • On the device: WP7 sync provider
  • In the cloud: SQL Azure sync end points and data stores

An application uses sync framework APIs to interact with the WP7 sync provider that can handle synchronization with the back-end data store. For more information about using Sync Framework for WP7, please visit MSDN site http://msdn.microsoft.com/library/gg507824.aspx.

This chapter’s sample applications AppDataSample and SampleCloudService provide a simple local-cloud storage model where both the cloud and the device client use an XML file to store user data. You can extend the example to use a SQL database in the cloud, which allows more structural data manipulation.

DATA STORAGE DESIGN CONSIDERATIONS

A critical problem with using local data is UI performance. A general rule of thumb is to avoid any storage access when the device is busy rendering graphics and media. If blocking data access is not absolutely needed, then it should be done in a background thread with reduced thread priority whenever possible. In addition, Microsoft recommends using buffered file access to reduce I/O operations.

The problem with the combination of local data and cloud storage occurs when there are multiple copies of the same data. It becomes a challenge to manage and update these copies, while at the same time providing the user with good performance. The places where a copy can reside include:

  • Data hosted in cloud storage, which can be as simple as some XML files, or as complex as a database consisting of a number of tables, views, or other data elements.
  • Data on supported mobile devices, which can be a SQLite database created by an Android client or an iOS client. Or a data file created and managed by a WP7 client.
  • Data on a desktop or a laptop computer, which can be created and managed by a stand-alone desktop application. This is a rare situation, as many applications choose to provide web-based access rather than a stand-alone desktop application.
  • Data managed by an HTML5 web browser, as offline storage is one of the new features supported by the new HTML5 standard.

For each data set, you must exercise care to resolve synchronization conflicts between existing data and a received update. One common approach is to use timestamps to compare the freshness of the data and choose the latest update. Another approach just prompts the user to determine what to keep, and then updates local data and the cloud accordingly.

Cloud data generally serves as the central data source so other data sets on clients can keep synchronizing with it. On a mobile device, an application must handle data in at least three locations, as shown in Figure 5-4: local database or files, memory data, and cloud data.

FIGURE 5-4: Application data model

image

The application can load data from a local database or a local file into memory, as well as save data to the database or the file. It may download data from cloud storage and update that with changes done on the device. It becomes a challenging issue to make better use of these assets to provide a good user experience and performance. There are a few synchronization strategies that you can apply to the scenario, specifically for client application design, as discussed below:

  • Real-time update: Any update on cloud data is pushed to the client by using push notifications. If the device application is running, then device local data is updated immediately; if it’s not running, then a push notification is sent to the device and gives the user a chance to launch the application and update the data. See Chapter 6 for more information on push notifications on the three platforms.

Conversely, any client-side update is pushed to the cloud right after a change has been made on the local copy.

This strategy is highly dependent on network connectivity. Also, frequent changes to the presented data on the UI may confuse the user. This strategy is required by those applications that offer real-time information such as flight information, game scores, and so on, since data freshness is of paramount importance to these applications.

  • Client start-stop update: A device application downloads the latest update from the cloud when it starts to run and uploads any changes to the cloud when it stops. Unless a user initiates a data synchronization operation, applications simply use the downloaded local copy while the application runs.

Many news and magazine applications that work well in offline mode and do not require real-time updates have adopted this strategy. These applications may react to network connectivity events and try to download the update from the cloud when network connectivity resumes. The downside is that application launching performance suffers when the initial update is slow. This is a problem across WP7, iOS, and Android. A work-around is to load local data first to unblock the UI thread, and then launch a background thread (such as using .NET ThreadPool) to perform cloud synchronization, and update the UI when the synchronization is done.

  • Scheduled update: An application can use a schedule to perform data synchronization, and a user can also specify periodical one-way or two-way updates. This is technically possible for applications on Android, where the system can create a background service to handle scheduled updates, even if the application itself isn’t running. There are two variants of this approach: one is to design the client service process so it launches periodic polls to its server for updates, and the other is to maintain a long-lived heartbeat connection between the client and the server so the server can push updates at any time without clients’ solicitation.

This strategy offers a balance between data refreshes and offline access, and has been used by many e-mail and social applications. This strategy has an impact on battery life as frequent updates may drain the battery quickly. A WP7 application cannot create a service to perform scheduled updates all the time, but it can do this when the application is running.

SUMMARY

This chapter has discussed application data storage for a WP7 application. WP7 provides isolated storage and serialization classes so an application can save and restore data easily. The isolated storage local setting class is used to store application settings. Microsoft suggests using cloud storage because WP7 doesn’t provide an on-device database engine. The chapter shows how to create a Windows Azure web service and use it to back up and restore data.

There are a few platform-agnostic design issues to consider when building applications on all three major platforms, such as choosing a good data synchronization strategy against performance and data freshness, while providing offline access. The chapter provides some design considerations for these issues. There are other interesting issues in this field that the chapter doesn’t cover, such as the use of third-party synchronization frameworks and data providers for WP7 and Android. Interested readers are encouraged to learn more by following the links in the chapter.

This chapter has been about using a hosted web service. The next chapter is dedicated to consuming standard HTTP web services and push notifications. Both of these data sources are important topics for web-enabled mobile applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.160.156