Adding Offline Capabilities
With the architecture you have created so far, you can also implement the core of an offline storage system. Many times, Microsoft Outlook is used as the poster child for offline functionality. Whenever the user has access to her Exchange server, either directly or over HTTP (in a fashion similar to the scenarios above), live data is being accessed, but when the connection is unavailable, data from a local offline data store is being used. This version of the data is not necessarily as up to date as the data on the Exchange server, but it is generally up to date enough to allow the user to work productively. Basically, the user sees the data as it was the last time it was accessed online.
The core concept is pretty simple. Take the data that is served up by the data services you created so far, and store it locally for later use. Then, create another data service that can access that offline data when everything else fails.
The following code snippet shows a relatively naïve approach to modify the SqlServerDataService to store all data that is queried through the ExecuteQuery()
public DataSet ExecuteQuery(IDbCommand Command,
DataSet ds = new DataSet();
SqlCommand objCommand = (SqlCommand)Command;
SqlDataAdapter adAdapter =
adAdapter.SelectCommand.Connection = null;
I am calling this a naïve approach, because the offline XML file gets overridden every time. So if you queried all customers whose last name starts with A, and then query all whose last name starts with B, the offline file would only contain the B customers. If you were to subsequently query invoice information, the file would contain a completely different set of data altogether. And to make matters worse, there is no easy way to tell what type of data is contained in the latest version.
This approach points us in the right direction in terms of what is fundamentally required: All the data that travels through one of the three data access methods (in all your live data services) needs to be intercepted and stored away for later use. XML files are only adequate for the simplest of uses. In most scenarios, you need a sophisticated local data store such as MSDE/SQL Express or a similarly capable database.
Once data is stored locally, creating a data service that operates on the local data source is mostly a variation of the SQL Server data service. The only part that deserves special mention is data modification. When the user updates data in the local data store, or adds new data altogether, those changes need to be applied locally, but you also need to keep track of all the records that have been modified and when, so you can later sync those changes back to the online version of the data store.
The implementation of this can happen in a number of ways. I like a variation that has the data access methods raise events whenever data is queried (ideally, those events are static/shared
, so it is relatively easy to hook up to them on a global basis). This allows for the creation of a single object that subscribes to the data access events of all kinds of data services. This object ideally queues a copy of the data away so it can be stored for offline use, possibly on a low priority background thread.
So the fundamental ideas behind building an offline data store similar to Outlook's offline data store are pretty straightforward and can be implemented in a completely generic fashion. However, there really is a bit more to it, and compared to many business applications, Outlook faces a much less complex problem. This is due to two facts: Outlook has relatively simple business rules and Outlook stores data in a fashion that is not comparable to most business applications. In Outlook, each user has an individual set of data. E-mail messages belong to one user and one user only. The same is true for contacts. Even potentially shared data such as calendar information is kept separated. If two users share the same appointment, they both get a unique copy.
Most business applications work differently. Often, complex business rules are needed, and offline scenarios may need special handling. For instance, an order for 1000 widgets entered offline may appear perfectly valid to the local business logic that relies on the last known snapshot of data. However, once the system is taken back online, it may discover that another sales person has sold the remaining stock of that widget, making the data entered offline invalid. In many such scenarios, there are no good generic answers as to how to handle them. Developers will have to implement scenario-specific conflict resolution logic so the system can be brought back into valid state.
The problem of shared data is a completely different problem. Outlook conveniently sidesteps this one completely, but you are not likely to get off the hook this easily. Fundamentally, you need to implement a concurrency management system. The appropriate approach depends on your scenario. Do you want to simply store the last version of a record? Do you want to approach the problem on a field by field basis? Do you want to use a data dictionary to define groups of fields that have to be updated together? (It is probably okay to save one user's version of an e-mail address and another user's version of the same record's phone number, but it is probably not okay to save one user's version of a city field and another user's ZIP code update of the same record.). Perhaps you may even want to ask the user to help resolve the problem in difficult cases. The choice of appropriate implementation is up to the developer and beyond the scope of this architectural article.
One other area of concern that should be mentioned at least briefly is that of security. It is highly recommended that whatever technology you choose to use for your client-side data store supports strong security. Security is of a particular concern for offline data because the probability of data theft is orders of magnitude greater than for desktop computers, as it is much easier to steel a laptop bag out of a car, than it is to carry a PC out of an office. Having the device stolen may set you back a couple of thousand dollars, but if your data is not secure and is therefore accessible to the thief, the potential damage is much greater. I am sure you wouldn't want to explain to a few hundred of your best clients why their credit card numbers got stolen out of your database.