
Update: The code for the sample application is now published.
In this blog, I will be talking about offline support for Windows. If you have been following my other blogs (or corresponding blogs for Android and iOS), you are already aware of the concept of a Store. You are probably aware that there is an Online Store and by extension, an Offline Store. Although I haven’t talked about an Offline Store explicitly, I have made a few subtle references to its existence in my previous blogs. An astute reader might have already guessed that an Online Store can be used when the device has network connection. So what about the Offline Store? A common mistake most people make, is that they only associate Offline Store with no network connection. While this is true (Offline Store is used with no network connection), an Offline Store can also be used when there is network connection. In fact, I would recommend using the Offline Store in all cases (if you want offline support) – and not use the Online Store at all. Of course, this would also depend on the business needs. But using the Offline Store regardless of network connectivity reduces the complexity of switching back and forth between Online and Offline Stores. The caveat is that the user might be working with stale data.
In the table below, I roughly compare the features of an Online Store and an Offline Store.
Online Store | Offline Store |
Can work with network connection only | Can work regardless of network connectivity |
Opening Online Store – straightforward | Opening Offline Store – requires more options |
HTTP request – roundtrip to server | HTTP request – reads from local ultralite database |
Very basic persistence using Technical Cache | Full-fledged persistence using ultralite database |
CRUD operations – accomplished by OData calls | CRUD operations – OData calls are intercepted and converted to SQL calls and executed against ultralite database |
No data latency | Data latency exists |
No concept of flush | Flush method pushes changes made locally to the backend |
No concept of refresh | Refresh method pushes changes made on the backend to the local ultralite database |
Data conflicts – very minimal | Data conflicts – a real possibility |
HTTP(S) protocol to transfer data between SMP Server and device | Mobilink protocol to transfer data between SMP Server and device |
The first time an Offline Store is opened, a lot of things happen. The Offline Store connects to the SMP Server and sends it the defining request. It is very critical to understand what constitutes a defining request. A defining request is an URL representing data fetched by an HTTP GET method that needs to be persisted. An application can have multiple defining requests.
Examples of defining requests… Note that each defining request corresponds to a single GET request.
Request 1 | BusinessPartners
SalesOrders
Items
| Data persisted on device BusinessPartners
SalesOrders
Items
Products
ProductDetails
|
Request 2 | SalesOrders
Items
| |
Request 3 | Products
ProductDetails
|
SMP Server queries the backend using the defining requests. The union of the data retrieved by all the defining requests is used to populate the database on the SMP Server. This prepopulated database is then sent to the device. Note that data is not duplicated on the device – just the union of the data retrieved by all the defining requests is persisted. For efficiency reasons, it is recommended not to have overlapping defining requests. However, even if you have overlapping defining requests, data will not be duplicated on the device.
Lot less happens during subsequent openings of the Offline Store. The application does not connect to SMP Server. Therefore application does not require network connection. Application simply opens the existing database on the device.
Store | Action |
Offline Store (first time opening) | Needs network connection Defining request sent to SMP Server SMP Server queries backend using defining requests Creates a new database with backend response Sends newly created database to device |
Offline Store (Subsequent openings) | Does not need network connection Simply opens existing database on device Does not connect to SMP Server |
Creating an Offline Store is straightforward. The constructor does not take any parameters.
this.Store = new SAP.Data.OData.Offline.Store.ODataOfflineStore(); |
Opening the Offline Store takes ODataOfflineStoreOptions as a parameter
await this.Store.OpenAsync(options); |
So, how do I create this “options” parameter? For this, you need to create the ODataOfflineStoreOptions object with the proper values. Thankfully, most values are intuitive. The following code snippet creates the ODataOfflineStoreOptions and populates it with the proper values.
var options = new SAP.Data.OData.Offline.Store.ODataOfflineStoreOptions(); var client = new SAP.Net.Http.HttpClient(new System.Net.Http.HttpClientHandler() {Credentials = new System.Net.NetworkCredential(“user”, “password”)}, true); // will be disposed by the store! client.DefaultRequestHeaders.TryAddWithoutValidation("X-SMP-APPCID", connectionId); client.DefaultRequestHeaders.TryAddWithoutValidation("X-SUP-APPCID", connectionId); client.ShouldHandleXcsrfToken = true; options.ConversationManager = client; options.Host = "10.4.64.212"; options.Port = 8080; options.ServiceRoot = "com.sap.flight"; options.EnableHttps = false; options.StoreName = "OfflineStore"; options.StoreEncryptionKey = "SuperSecretEncryptionKey"; options.URLSuffix = ""; options.AddDefiningRequest("TravelagencyDR""TravelagencyCollection"false); options.EnableRepeatableRequests = true; |
Note: For operations that change state (for example, inserting a new resource) re-issuing the request may result in an undesired state (for example, two orders placed). Set EnableRepeatableRequests property to true to avoid such situations. Note that the backend OData Service must support this feature. SAP Gateway supports this feature.
CRUD operations can be performed on the Offline Store after successfully opening the Offline Store. The syntax for CRUD operations on an Offline Store is identical to the syntax for an Online Store. The only difference is that the data is retrieved from the locally persisted ultralite database instead of from the backend.
CREATE
var execution = store.ScheduleCreateEntity(entity, collectionName); var response = await execution.Response; |
READ
var execution = store.ScheduleReadEntitySet(collectionName); var response = await execution.Response; |
UPDATE
var execution = store.ScheduleUpdateEntity(copiedEntity); var response = await execution.Response; |
DELETE
var execution = store.ScheduleDeleteEntity(entity); var response = await execution.Response; |
Flush and refresh allows the locally persisted data to be synchronized with the backend data. Both Flush and Refresh methods require network connection. Flush allows changes made locally on the device to be applied on the backend in an asynchronous fashion. Refresh on the other hand, allows changes made on the backend to be downloaded to the device. An important thing to note when calling the Flush method is that all the changes made locally on the device are submitted. The SDK currently does not support sending part of the changes. However, Refresh method has the option of downloading part of the backend changes based on defining request.
Flush method | Refresh method |
Requires network connection | Requires network connection |
Changes made locally submitted to backend | Changes made on backend downloaded to device |
This call is asynchronous | This call is asynchronous |
All changes are submitted – Cannot submit part of the changes | Developer has the option of downloading part of backend changes based on defining request |
Call Flush before calling Refresh | Call Flush before calling Refresh |
FLUSH
await this.Store.ScheduleFlushQueuedRequestsAsync(); |
REFRESH
await this.Store.ScheduleRefreshAsync(); OR await this.Store.ScheduleRefreshAsync(definingrequest); |
Please feel free to post any comments or questions that you might have. I will try to answer them as soon as I can. Hopefully, these blogs have given you enough insights into the Windows SDK to start building new mobile applications. Good luck !
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
16 | |
15 | |
14 | |
11 | |
11 | |
11 | |
10 | |
9 | |
9 | |
8 |